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