linux/fs/btrfs/inode-item.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 "disk-io.h"
  21#include "hash.h"
  22#include "transaction.h"
  23#include "print-tree.h"
  24
  25static int find_name_in_backref(struct btrfs_path *path, const char *name,
  26                         int name_len, struct btrfs_inode_ref **ref_ret)
  27{
  28        struct extent_buffer *leaf;
  29        struct btrfs_inode_ref *ref;
  30        unsigned long ptr;
  31        unsigned long name_ptr;
  32        u32 item_size;
  33        u32 cur_offset = 0;
  34        int len;
  35
  36        leaf = path->nodes[0];
  37        item_size = btrfs_item_size_nr(leaf, path->slots[0]);
  38        ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
  39        while (cur_offset < item_size) {
  40                ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
  41                len = btrfs_inode_ref_name_len(leaf, ref);
  42                name_ptr = (unsigned long)(ref + 1);
  43                cur_offset += len + sizeof(*ref);
  44                if (len != name_len)
  45                        continue;
  46                if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) {
  47                        *ref_ret = ref;
  48                        return 1;
  49                }
  50        }
  51        return 0;
  52}
  53
  54int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid,
  55                                   const char *name, int name_len,
  56                                   struct btrfs_inode_extref **extref_ret)
  57{
  58        struct extent_buffer *leaf;
  59        struct btrfs_inode_extref *extref;
  60        unsigned long ptr;
  61        unsigned long name_ptr;
  62        u32 item_size;
  63        u32 cur_offset = 0;
  64        int ref_name_len;
  65
  66        leaf = path->nodes[0];
  67        item_size = btrfs_item_size_nr(leaf, path->slots[0]);
  68        ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
  69
  70        /*
  71         * Search all extended backrefs in this item. We're only
  72         * looking through any collisions so most of the time this is
  73         * just going to compare against one buffer. If all is well,
  74         * we'll return success and the inode ref object.
  75         */
  76        while (cur_offset < item_size) {
  77                extref = (struct btrfs_inode_extref *) (ptr + cur_offset);
  78                name_ptr = (unsigned long)(&extref->name);
  79                ref_name_len = btrfs_inode_extref_name_len(leaf, extref);
  80
  81                if (ref_name_len == name_len &&
  82                    btrfs_inode_extref_parent(leaf, extref) == ref_objectid &&
  83                    (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)) {
  84                        if (extref_ret)
  85                                *extref_ret = extref;
  86                        return 1;
  87                }
  88
  89                cur_offset += ref_name_len + sizeof(*extref);
  90        }
  91        return 0;
  92}
  93
  94static struct btrfs_inode_ref *
  95btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans,
  96                       struct btrfs_root *root,
  97                       struct btrfs_path *path,
  98                       const char *name, int name_len,
  99                       u64 inode_objectid, u64 ref_objectid, int ins_len,
 100                       int cow)
 101{
 102        int ret;
 103        struct btrfs_key key;
 104        struct btrfs_inode_ref *ref;
 105
 106        key.objectid = inode_objectid;
 107        key.type = BTRFS_INODE_REF_KEY;
 108        key.offset = ref_objectid;
 109
 110        ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
 111        if (ret < 0)
 112                return ERR_PTR(ret);
 113        if (ret > 0)
 114                return NULL;
 115        if (!find_name_in_backref(path, name, name_len, &ref))
 116                return NULL;
 117        return ref;
 118}
 119
 120/* Returns NULL if no extref found */
 121struct btrfs_inode_extref *
 122btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
 123                          struct btrfs_root *root,
 124                          struct btrfs_path *path,
 125                          const char *name, int name_len,
 126                          u64 inode_objectid, u64 ref_objectid, int ins_len,
 127                          int cow)
 128{
 129        int ret;
 130        struct btrfs_key key;
 131        struct btrfs_inode_extref *extref;
 132
 133        key.objectid = inode_objectid;
 134        key.type = BTRFS_INODE_EXTREF_KEY;
 135        key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
 136
 137        ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
 138        if (ret < 0)
 139                return ERR_PTR(ret);
 140        if (ret > 0)
 141                return NULL;
 142        if (!btrfs_find_name_in_ext_backref(path, ref_objectid, name, name_len, &extref))
 143                return NULL;
 144        return extref;
 145}
 146
 147int btrfs_get_inode_ref_index(struct btrfs_trans_handle *trans,
 148                              struct btrfs_root *root,
 149                              struct btrfs_path *path,
 150                              const char *name, int name_len,
 151                              u64 inode_objectid, u64 ref_objectid, int mod,
 152                              u64 *ret_index)
 153{
 154        struct btrfs_inode_ref *ref;
 155        struct btrfs_inode_extref *extref;
 156        int ins_len = mod < 0 ? -1 : 0;
 157        int cow = mod != 0;
 158
 159        ref = btrfs_lookup_inode_ref(trans, root, path, name, name_len,
 160                                     inode_objectid, ref_objectid, ins_len,
 161                                     cow);
 162        if (IS_ERR(ref))
 163                return PTR_ERR(ref);
 164
 165        if (ref != NULL) {
 166                *ret_index = btrfs_inode_ref_index(path->nodes[0], ref);
 167                return 0;
 168        }
 169
 170        btrfs_release_path(path);
 171
 172        extref = btrfs_lookup_inode_extref(trans, root, path, name,
 173                                           name_len, inode_objectid,
 174                                           ref_objectid, ins_len, cow);
 175        if (IS_ERR(extref))
 176                return PTR_ERR(extref);
 177
 178        if (extref) {
 179                *ret_index = btrfs_inode_extref_index(path->nodes[0], extref);
 180                return 0;
 181        }
 182
 183        return -ENOENT;
 184}
 185
 186static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
 187                                  struct btrfs_root *root,
 188                                  const char *name, int name_len,
 189                                  u64 inode_objectid, u64 ref_objectid,
 190                                  u64 *index)
 191{
 192        struct btrfs_path *path;
 193        struct btrfs_key key;
 194        struct btrfs_inode_extref *extref;
 195        struct extent_buffer *leaf;
 196        int ret;
 197        int del_len = name_len + sizeof(*extref);
 198        unsigned long ptr;
 199        unsigned long item_start;
 200        u32 item_size;
 201
 202        key.objectid = inode_objectid;
 203        btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY);
 204        key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
 205
 206        path = btrfs_alloc_path();
 207        if (!path)
 208                return -ENOMEM;
 209
 210        path->leave_spinning = 1;
 211
 212        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
 213        if (ret > 0)
 214                ret = -ENOENT;
 215        if (ret < 0)
 216                goto out;
 217
 218        /*
 219         * Sanity check - did we find the right item for this name?
 220         * This should always succeed so error here will make the FS
 221         * readonly.
 222         */
 223        if (!btrfs_find_name_in_ext_backref(path, ref_objectid,
 224                                            name, name_len, &extref)) {
 225                btrfs_std_error(root->fs_info, -ENOENT);
 226                ret = -EROFS;
 227                goto out;
 228        }
 229
 230        leaf = path->nodes[0];
 231        item_size = btrfs_item_size_nr(leaf, path->slots[0]);
 232        if (index)
 233                *index = btrfs_inode_extref_index(leaf, extref);
 234
 235        if (del_len == item_size) {
 236                /*
 237                 * Common case only one ref in the item, remove the
 238                 * whole item.
 239                 */
 240                ret = btrfs_del_item(trans, root, path);
 241                goto out;
 242        }
 243
 244        ptr = (unsigned long)extref;
 245        item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
 246
 247        memmove_extent_buffer(leaf, ptr, ptr + del_len,
 248                              item_size - (ptr + del_len - item_start));
 249
 250        btrfs_truncate_item(root, path, item_size - del_len, 1);
 251
 252out:
 253        btrfs_free_path(path);
 254
 255        return ret;
 256}
 257
 258int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
 259                        struct btrfs_root *root,
 260                        const char *name, int name_len,
 261                        u64 inode_objectid, u64 ref_objectid, u64 *index)
 262{
 263        struct btrfs_path *path;
 264        struct btrfs_key key;
 265        struct btrfs_inode_ref *ref;
 266        struct extent_buffer *leaf;
 267        unsigned long ptr;
 268        unsigned long item_start;
 269        u32 item_size;
 270        u32 sub_item_len;
 271        int ret;
 272        int search_ext_refs = 0;
 273        int del_len = name_len + sizeof(*ref);
 274
 275        key.objectid = inode_objectid;
 276        key.offset = ref_objectid;
 277        btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
 278
 279        path = btrfs_alloc_path();
 280        if (!path)
 281                return -ENOMEM;
 282
 283        path->leave_spinning = 1;
 284
 285        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
 286        if (ret > 0) {
 287                ret = -ENOENT;
 288                search_ext_refs = 1;
 289                goto out;
 290        } else if (ret < 0) {
 291                goto out;
 292        }
 293        if (!find_name_in_backref(path, name, name_len, &ref)) {
 294                ret = -ENOENT;
 295                search_ext_refs = 1;
 296                goto out;
 297        }
 298        leaf = path->nodes[0];
 299        item_size = btrfs_item_size_nr(leaf, path->slots[0]);
 300
 301        if (index)
 302                *index = btrfs_inode_ref_index(leaf, ref);
 303
 304        if (del_len == item_size) {
 305                ret = btrfs_del_item(trans, root, path);
 306                goto out;
 307        }
 308        ptr = (unsigned long)ref;
 309        sub_item_len = name_len + sizeof(*ref);
 310        item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
 311        memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
 312                              item_size - (ptr + sub_item_len - item_start));
 313        btrfs_truncate_item(root, path, item_size - sub_item_len, 1);
 314out:
 315        btrfs_free_path(path);
 316
 317        if (search_ext_refs) {
 318                /*
 319                 * No refs were found, or we could not find the
 320                 * name in our ref array. Find and remove the extended
 321                 * inode ref then.
 322                 */
 323                return btrfs_del_inode_extref(trans, root, name, name_len,
 324                                              inode_objectid, ref_objectid, index);
 325        }
 326
 327        return ret;
 328}
 329
 330/*
 331 * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree.
 332 *
 333 * The caller must have checked against BTRFS_LINK_MAX already.
 334 */
 335static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
 336                                     struct btrfs_root *root,
 337                                     const char *name, int name_len,
 338                                     u64 inode_objectid, u64 ref_objectid, u64 index)
 339{
 340        struct btrfs_inode_extref *extref;
 341        int ret;
 342        int ins_len = name_len + sizeof(*extref);
 343        unsigned long ptr;
 344        struct btrfs_path *path;
 345        struct btrfs_key key;
 346        struct extent_buffer *leaf;
 347        struct btrfs_item *item;
 348
 349        key.objectid = inode_objectid;
 350        key.type = BTRFS_INODE_EXTREF_KEY;
 351        key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
 352
 353        path = btrfs_alloc_path();
 354        if (!path)
 355                return -ENOMEM;
 356
 357        path->leave_spinning = 1;
 358        ret = btrfs_insert_empty_item(trans, root, path, &key,
 359                                      ins_len);
 360        if (ret == -EEXIST) {
 361                if (btrfs_find_name_in_ext_backref(path, ref_objectid,
 362                                                   name, name_len, NULL))
 363                        goto out;
 364
 365                btrfs_extend_item(root, path, ins_len);
 366                ret = 0;
 367        }
 368        if (ret < 0)
 369                goto out;
 370
 371        leaf = path->nodes[0];
 372        item = btrfs_item_nr(leaf, path->slots[0]);
 373        ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char);
 374        ptr += btrfs_item_size(leaf, item) - ins_len;
 375        extref = (struct btrfs_inode_extref *)ptr;
 376
 377        btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len);
 378        btrfs_set_inode_extref_index(path->nodes[0], extref, index);
 379        btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid);
 380
 381        ptr = (unsigned long)&extref->name;
 382        write_extent_buffer(path->nodes[0], name, ptr, name_len);
 383        btrfs_mark_buffer_dirty(path->nodes[0]);
 384
 385out:
 386        btrfs_free_path(path);
 387        return ret;
 388}
 389
 390/* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
 391int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
 392                           struct btrfs_root *root,
 393                           const char *name, int name_len,
 394                           u64 inode_objectid, u64 ref_objectid, u64 index)
 395{
 396        struct btrfs_path *path;
 397        struct btrfs_key key;
 398        struct btrfs_inode_ref *ref;
 399        unsigned long ptr;
 400        int ret;
 401        int ins_len = name_len + sizeof(*ref);
 402
 403        key.objectid = inode_objectid;
 404        key.offset = ref_objectid;
 405        btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
 406
 407        path = btrfs_alloc_path();
 408        if (!path)
 409                return -ENOMEM;
 410
 411        path->leave_spinning = 1;
 412        ret = btrfs_insert_empty_item(trans, root, path, &key,
 413                                      ins_len);
 414        if (ret == -EEXIST) {
 415                u32 old_size;
 416
 417                if (find_name_in_backref(path, name, name_len, &ref))
 418                        goto out;
 419
 420                old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
 421                btrfs_extend_item(root, path, ins_len);
 422                ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
 423                                     struct btrfs_inode_ref);
 424                ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
 425                btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
 426                btrfs_set_inode_ref_index(path->nodes[0], ref, index);
 427                ptr = (unsigned long)(ref + 1);
 428                ret = 0;
 429        } else if (ret < 0) {
 430                if (ret == -EOVERFLOW)
 431                        ret = -EMLINK;
 432                goto out;
 433        } else {
 434                ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
 435                                     struct btrfs_inode_ref);
 436                btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
 437                btrfs_set_inode_ref_index(path->nodes[0], ref, index);
 438                ptr = (unsigned long)(ref + 1);
 439        }
 440        write_extent_buffer(path->nodes[0], name, ptr, name_len);
 441        btrfs_mark_buffer_dirty(path->nodes[0]);
 442
 443out:
 444        btrfs_free_path(path);
 445
 446        if (ret == -EMLINK) {
 447                struct btrfs_super_block *disk_super = root->fs_info->super_copy;
 448                /* We ran out of space in the ref array. Need to
 449                 * add an extended ref. */
 450                if (btrfs_super_incompat_flags(disk_super)
 451                    & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
 452                        ret = btrfs_insert_inode_extref(trans, root, name,
 453                                                        name_len,
 454                                                        inode_objectid,
 455                                                        ref_objectid, index);
 456        }
 457
 458        return ret;
 459}
 460
 461int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
 462                             struct btrfs_root *root,
 463                             struct btrfs_path *path, u64 objectid)
 464{
 465        struct btrfs_key key;
 466        int ret;
 467        key.objectid = objectid;
 468        btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
 469        key.offset = 0;
 470
 471        ret = btrfs_insert_empty_item(trans, root, path, &key,
 472                                      sizeof(struct btrfs_inode_item));
 473        return ret;
 474}
 475
 476int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
 477                       *root, struct btrfs_path *path,
 478                       struct btrfs_key *location, int mod)
 479{
 480        int ins_len = mod < 0 ? -1 : 0;
 481        int cow = mod != 0;
 482        int ret;
 483        int slot;
 484        struct extent_buffer *leaf;
 485        struct btrfs_key found_key;
 486
 487        ret = btrfs_search_slot(trans, root, location, path, ins_len, cow);
 488        if (ret > 0 && btrfs_key_type(location) == BTRFS_ROOT_ITEM_KEY &&
 489            location->offset == (u64)-1 && path->slots[0] != 0) {
 490                slot = path->slots[0] - 1;
 491                leaf = path->nodes[0];
 492                btrfs_item_key_to_cpu(leaf, &found_key, slot);
 493                if (found_key.objectid == location->objectid &&
 494                    btrfs_key_type(&found_key) == btrfs_key_type(location)) {
 495                        path->slots[0]--;
 496                        return 0;
 497                }
 498        }
 499        return ret;
 500}
 501