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