linux/fs/btrfs/dir-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
  24/*
  25 * insert a name into a directory, doing overflow properly if there is a hash
  26 * collision.  data_size indicates how big the item inserted should be.  On
  27 * success a struct btrfs_dir_item pointer is returned, otherwise it is
  28 * an ERR_PTR.
  29 *
  30 * The name is not copied into the dir item, you have to do that yourself.
  31 */
  32static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
  33                                                   *trans,
  34                                                   struct btrfs_root *root,
  35                                                   struct btrfs_path *path,
  36                                                   struct btrfs_key *cpu_key,
  37                                                   u32 data_size,
  38                                                   const char *name,
  39                                                   int name_len)
  40{
  41        int ret;
  42        char *ptr;
  43        struct btrfs_item *item;
  44        struct extent_buffer *leaf;
  45
  46        ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
  47        if (ret == -EEXIST) {
  48                struct btrfs_dir_item *di;
  49                di = btrfs_match_dir_item_name(root, path, name, name_len);
  50                if (di)
  51                        return ERR_PTR(-EEXIST);
  52                ret = btrfs_extend_item(trans, root, path, data_size);
  53                WARN_ON(ret > 0);
  54        }
  55        if (ret < 0)
  56                return ERR_PTR(ret);
  57        WARN_ON(ret > 0);
  58        leaf = path->nodes[0];
  59        item = btrfs_item_nr(leaf, path->slots[0]);
  60        ptr = btrfs_item_ptr(leaf, path->slots[0], char);
  61        BUG_ON(data_size > btrfs_item_size(leaf, item));
  62        ptr += btrfs_item_size(leaf, item) - data_size;
  63        return (struct btrfs_dir_item *)ptr;
  64}
  65
  66/*
  67 * xattrs work a lot like directories, this inserts an xattr item
  68 * into the tree
  69 */
  70int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
  71                            struct btrfs_root *root,
  72                            struct btrfs_path *path, u64 objectid,
  73                            const char *name, u16 name_len,
  74                            const void *data, u16 data_len)
  75{
  76        int ret = 0;
  77        struct btrfs_dir_item *dir_item;
  78        unsigned long name_ptr, data_ptr;
  79        struct btrfs_key key, location;
  80        struct btrfs_disk_key disk_key;
  81        struct extent_buffer *leaf;
  82        u32 data_size;
  83
  84        BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root));
  85
  86        key.objectid = objectid;
  87        btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
  88        key.offset = btrfs_name_hash(name, name_len);
  89
  90        data_size = sizeof(*dir_item) + name_len + data_len;
  91        dir_item = insert_with_overflow(trans, root, path, &key, data_size,
  92                                        name, name_len);
  93        /*
  94         * FIXME: at some point we should handle xattr's that are larger than
  95         * what we can fit in our leaf.  We set location to NULL b/c we arent
  96         * pointing at anything else, that will change if we store the xattr
  97         * data in a separate inode.
  98         */
  99        BUG_ON(IS_ERR(dir_item));
 100        memset(&location, 0, sizeof(location));
 101
 102        leaf = path->nodes[0];
 103        btrfs_cpu_key_to_disk(&disk_key, &location);
 104        btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
 105        btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
 106        btrfs_set_dir_name_len(leaf, dir_item, name_len);
 107        btrfs_set_dir_transid(leaf, dir_item, trans->transid);
 108        btrfs_set_dir_data_len(leaf, dir_item, data_len);
 109        name_ptr = (unsigned long)(dir_item + 1);
 110        data_ptr = (unsigned long)((char *)name_ptr + name_len);
 111
 112        write_extent_buffer(leaf, name, name_ptr, name_len);
 113        write_extent_buffer(leaf, data, data_ptr, data_len);
 114        btrfs_mark_buffer_dirty(path->nodes[0]);
 115
 116        return ret;
 117}
 118
 119/*
 120 * insert a directory item in the tree, doing all the magic for
 121 * both indexes. 'dir' indicates which objectid to insert it into,
 122 * 'location' is the key to stuff into the directory item, 'type' is the
 123 * type of the inode we're pointing to, and 'index' is the sequence number
 124 * to use for the second index (if one is created).
 125 */
 126int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
 127                          *root, const char *name, int name_len, u64 dir,
 128                          struct btrfs_key *location, u8 type, u64 index)
 129{
 130        int ret = 0;
 131        int ret2 = 0;
 132        struct btrfs_path *path;
 133        struct btrfs_dir_item *dir_item;
 134        struct extent_buffer *leaf;
 135        unsigned long name_ptr;
 136        struct btrfs_key key;
 137        struct btrfs_disk_key disk_key;
 138        u32 data_size;
 139
 140        key.objectid = dir;
 141        btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
 142        key.offset = btrfs_name_hash(name, name_len);
 143
 144        path = btrfs_alloc_path();
 145        path->leave_spinning = 1;
 146
 147        data_size = sizeof(*dir_item) + name_len;
 148        dir_item = insert_with_overflow(trans, root, path, &key, data_size,
 149                                        name, name_len);
 150        if (IS_ERR(dir_item)) {
 151                ret = PTR_ERR(dir_item);
 152                if (ret == -EEXIST)
 153                        goto second_insert;
 154                goto out;
 155        }
 156
 157        leaf = path->nodes[0];
 158        btrfs_cpu_key_to_disk(&disk_key, location);
 159        btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
 160        btrfs_set_dir_type(leaf, dir_item, type);
 161        btrfs_set_dir_data_len(leaf, dir_item, 0);
 162        btrfs_set_dir_name_len(leaf, dir_item, name_len);
 163        btrfs_set_dir_transid(leaf, dir_item, trans->transid);
 164        name_ptr = (unsigned long)(dir_item + 1);
 165
 166        write_extent_buffer(leaf, name, name_ptr, name_len);
 167        btrfs_mark_buffer_dirty(leaf);
 168
 169second_insert:
 170        /* FIXME, use some real flag for selecting the extra index */
 171        if (root == root->fs_info->tree_root) {
 172                ret = 0;
 173                goto out;
 174        }
 175        btrfs_release_path(root, path);
 176
 177        btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
 178        key.offset = index;
 179        dir_item = insert_with_overflow(trans, root, path, &key, data_size,
 180                                        name, name_len);
 181        if (IS_ERR(dir_item)) {
 182                ret2 = PTR_ERR(dir_item);
 183                goto out;
 184        }
 185        leaf = path->nodes[0];
 186        btrfs_cpu_key_to_disk(&disk_key, location);
 187        btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
 188        btrfs_set_dir_type(leaf, dir_item, type);
 189        btrfs_set_dir_data_len(leaf, dir_item, 0);
 190        btrfs_set_dir_name_len(leaf, dir_item, name_len);
 191        btrfs_set_dir_transid(leaf, dir_item, trans->transid);
 192        name_ptr = (unsigned long)(dir_item + 1);
 193        write_extent_buffer(leaf, name, name_ptr, name_len);
 194        btrfs_mark_buffer_dirty(leaf);
 195out:
 196        btrfs_free_path(path);
 197        if (ret)
 198                return ret;
 199        if (ret2)
 200                return ret2;
 201        return 0;
 202}
 203
 204/*
 205 * lookup a directory item based on name.  'dir' is the objectid
 206 * we're searching in, and 'mod' tells us if you plan on deleting the
 207 * item (use mod < 0) or changing the options (use mod > 0)
 208 */
 209struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
 210                                             struct btrfs_root *root,
 211                                             struct btrfs_path *path, u64 dir,
 212                                             const char *name, int name_len,
 213                                             int mod)
 214{
 215        int ret;
 216        struct btrfs_key key;
 217        int ins_len = mod < 0 ? -1 : 0;
 218        int cow = mod != 0;
 219        struct btrfs_key found_key;
 220        struct extent_buffer *leaf;
 221
 222        key.objectid = dir;
 223        btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
 224
 225        key.offset = btrfs_name_hash(name, name_len);
 226
 227        ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
 228        if (ret < 0)
 229                return ERR_PTR(ret);
 230        if (ret > 0) {
 231                if (path->slots[0] == 0)
 232                        return NULL;
 233                path->slots[0]--;
 234        }
 235
 236        leaf = path->nodes[0];
 237        btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
 238
 239        if (found_key.objectid != dir ||
 240            btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY ||
 241            found_key.offset != key.offset)
 242                return NULL;
 243
 244        return btrfs_match_dir_item_name(root, path, name, name_len);
 245}
 246
 247/*
 248 * lookup a directory item based on index.  'dir' is the objectid
 249 * we're searching in, and 'mod' tells us if you plan on deleting the
 250 * item (use mod < 0) or changing the options (use mod > 0)
 251 *
 252 * The name is used to make sure the index really points to the name you were
 253 * looking for.
 254 */
 255struct btrfs_dir_item *
 256btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
 257                            struct btrfs_root *root,
 258                            struct btrfs_path *path, u64 dir,
 259                            u64 objectid, const char *name, int name_len,
 260                            int mod)
 261{
 262        int ret;
 263        struct btrfs_key key;
 264        int ins_len = mod < 0 ? -1 : 0;
 265        int cow = mod != 0;
 266
 267        key.objectid = dir;
 268        btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
 269        key.offset = objectid;
 270
 271        ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
 272        if (ret < 0)
 273                return ERR_PTR(ret);
 274        if (ret > 0)
 275                return ERR_PTR(-ENOENT);
 276        return btrfs_match_dir_item_name(root, path, name, name_len);
 277}
 278
 279struct btrfs_dir_item *
 280btrfs_search_dir_index_item(struct btrfs_root *root,
 281                            struct btrfs_path *path, u64 dirid,
 282                            const char *name, int name_len)
 283{
 284        struct extent_buffer *leaf;
 285        struct btrfs_dir_item *di;
 286        struct btrfs_key key;
 287        u32 nritems;
 288        int ret;
 289
 290        key.objectid = dirid;
 291        key.type = BTRFS_DIR_INDEX_KEY;
 292        key.offset = 0;
 293
 294        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 295        if (ret < 0)
 296                return ERR_PTR(ret);
 297
 298        leaf = path->nodes[0];
 299        nritems = btrfs_header_nritems(leaf);
 300
 301        while (1) {
 302                if (path->slots[0] >= nritems) {
 303                        ret = btrfs_next_leaf(root, path);
 304                        if (ret < 0)
 305                                return ERR_PTR(ret);
 306                        if (ret > 0)
 307                                break;
 308                        leaf = path->nodes[0];
 309                        nritems = btrfs_header_nritems(leaf);
 310                        continue;
 311                }
 312
 313                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 314                if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY)
 315                        break;
 316
 317                di = btrfs_match_dir_item_name(root, path, name, name_len);
 318                if (di)
 319                        return di;
 320
 321                path->slots[0]++;
 322        }
 323        return NULL;
 324}
 325
 326struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
 327                                          struct btrfs_root *root,
 328                                          struct btrfs_path *path, u64 dir,
 329                                          const char *name, u16 name_len,
 330                                          int mod)
 331{
 332        int ret;
 333        struct btrfs_key key;
 334        int ins_len = mod < 0 ? -1 : 0;
 335        int cow = mod != 0;
 336        struct btrfs_key found_key;
 337        struct extent_buffer *leaf;
 338
 339        key.objectid = dir;
 340        btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
 341        key.offset = btrfs_name_hash(name, name_len);
 342        ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
 343        if (ret < 0)
 344                return ERR_PTR(ret);
 345        if (ret > 0) {
 346                if (path->slots[0] == 0)
 347                        return NULL;
 348                path->slots[0]--;
 349        }
 350
 351        leaf = path->nodes[0];
 352        btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
 353
 354        if (found_key.objectid != dir ||
 355            btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY ||
 356            found_key.offset != key.offset)
 357                return NULL;
 358
 359        return btrfs_match_dir_item_name(root, path, name, name_len);
 360}
 361
 362/*
 363 * helper function to look at the directory item pointed to by 'path'
 364 * this walks through all the entries in a dir item and finds one
 365 * for a specific name.
 366 */
 367struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
 368                              struct btrfs_path *path,
 369                              const char *name, int name_len)
 370{
 371        struct btrfs_dir_item *dir_item;
 372        unsigned long name_ptr;
 373        u32 total_len;
 374        u32 cur = 0;
 375        u32 this_len;
 376        struct extent_buffer *leaf;
 377
 378        leaf = path->nodes[0];
 379        dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
 380        total_len = btrfs_item_size_nr(leaf, path->slots[0]);
 381        while (cur < total_len) {
 382                this_len = sizeof(*dir_item) +
 383                        btrfs_dir_name_len(leaf, dir_item) +
 384                        btrfs_dir_data_len(leaf, dir_item);
 385                name_ptr = (unsigned long)(dir_item + 1);
 386
 387                if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
 388                    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
 389                        return dir_item;
 390
 391                cur += this_len;
 392                dir_item = (struct btrfs_dir_item *)((char *)dir_item +
 393                                                     this_len);
 394        }
 395        return NULL;
 396}
 397
 398/*
 399 * given a pointer into a directory item, delete it.  This
 400 * handles items that have more than one entry in them.
 401 */
 402int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
 403                              struct btrfs_root *root,
 404                              struct btrfs_path *path,
 405                              struct btrfs_dir_item *di)
 406{
 407
 408        struct extent_buffer *leaf;
 409        u32 sub_item_len;
 410        u32 item_len;
 411        int ret = 0;
 412
 413        leaf = path->nodes[0];
 414        sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
 415                btrfs_dir_data_len(leaf, di);
 416        item_len = btrfs_item_size_nr(leaf, path->slots[0]);
 417        if (sub_item_len == item_len) {
 418                ret = btrfs_del_item(trans, root, path);
 419        } else {
 420                /* MARKER */
 421                unsigned long ptr = (unsigned long)di;
 422                unsigned long start;
 423
 424                start = btrfs_item_ptr_offset(leaf, path->slots[0]);
 425                memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
 426                        item_len - (ptr + sub_item_len - start));
 427                ret = btrfs_truncate_item(trans, root, path,
 428                                          item_len - sub_item_len, 1);
 429        }
 430        return ret;
 431}
 432