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
 173static struct btrfs_dir_item *btrfs_lookup_match_dir(
 174                        struct btrfs_trans_handle *trans,
 175                        struct btrfs_root *root, struct btrfs_path *path,
 176                        struct btrfs_key *key, const char *name,
 177                        int name_len, int mod)
 178{
 179        const int ins_len = (mod < 0 ? -1 : 0);
 180        const int cow = (mod != 0);
 181        int ret;
 182
 183        ret = btrfs_search_slot(trans, root, key, path, ins_len, cow);
 184        if (ret < 0)
 185                return ERR_PTR(ret);
 186        if (ret > 0)
 187                return ERR_PTR(-ENOENT);
 188
 189        return btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
 190}
 191
 192/*
 193 * Lookup for a directory item by name.
 194 *
 195 * @trans:      The transaction handle to use. Can be NULL if @mod is 0.
 196 * @root:       The root of the target tree.
 197 * @path:       Path to use for the search.
 198 * @dir:        The inode number (objectid) of the directory.
 199 * @name:       The name associated to the directory entry we are looking for.
 200 * @name_len:   The length of the name.
 201 * @mod:        Used to indicate if the tree search is meant for a read only
 202 *              lookup, for a modification lookup or for a deletion lookup, so
 203 *              its value should be 0, 1 or -1, respectively.
 204 *
 205 * Returns: NULL if the dir item does not exists, an error pointer if an error
 206 * happened, or a pointer to a dir item if a dir item exists for the given name.
 207 */
 208struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
 209                                             struct btrfs_root *root,
 210                                             struct btrfs_path *path, u64 dir,
 211                                             const char *name, int name_len,
 212                                             int mod)
 213{
 214        struct btrfs_key key;
 215        struct btrfs_dir_item *di;
 216
 217        key.objectid = dir;
 218        key.type = BTRFS_DIR_ITEM_KEY;
 219        key.offset = btrfs_name_hash(name, name_len);
 220
 221        di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
 222        if (IS_ERR(di) && PTR_ERR(di) == -ENOENT)
 223                return NULL;
 224
 225        return di;
 226}
 227
 228int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
 229                                   const char *name, int name_len)
 230{
 231        int ret;
 232        struct btrfs_key key;
 233        struct btrfs_dir_item *di;
 234        int data_size;
 235        struct extent_buffer *leaf;
 236        int slot;
 237        struct btrfs_path *path;
 238
 239        path = btrfs_alloc_path();
 240        if (!path)
 241                return -ENOMEM;
 242
 243        key.objectid = dir;
 244        key.type = BTRFS_DIR_ITEM_KEY;
 245        key.offset = btrfs_name_hash(name, name_len);
 246
 247        di = btrfs_lookup_match_dir(NULL, root, path, &key, name, name_len, 0);
 248        if (IS_ERR(di)) {
 249                ret = PTR_ERR(di);
 250                /* Nothing found, we're safe */
 251                if (ret == -ENOENT) {
 252                        ret = 0;
 253                        goto out;
 254                }
 255
 256                if (ret < 0)
 257                        goto out;
 258        }
 259
 260        /* we found an item, look for our name in the item */
 261        if (di) {
 262                /* our exact name was found */
 263                ret = -EEXIST;
 264                goto out;
 265        }
 266
 267        /*
 268         * see if there is room in the item to insert this
 269         * name
 270         */
 271        data_size = sizeof(*di) + name_len;
 272        leaf = path->nodes[0];
 273        slot = path->slots[0];
 274        if (data_size + btrfs_item_size_nr(leaf, slot) +
 275            sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
 276                ret = -EOVERFLOW;
 277        } else {
 278                /* plenty of insertion room */
 279                ret = 0;
 280        }
 281out:
 282        btrfs_free_path(path);
 283        return ret;
 284}
 285
 286/*
 287 * Lookup for a directory index item by name and index number.
 288 *
 289 * @trans:      The transaction handle to use. Can be NULL if @mod is 0.
 290 * @root:       The root of the target tree.
 291 * @path:       Path to use for the search.
 292 * @dir:        The inode number (objectid) of the directory.
 293 * @index:      The index number.
 294 * @name:       The name associated to the directory entry we are looking for.
 295 * @name_len:   The length of the name.
 296 * @mod:        Used to indicate if the tree search is meant for a read only
 297 *              lookup, for a modification lookup or for a deletion lookup, so
 298 *              its value should be 0, 1 or -1, respectively.
 299 *
 300 * Returns: NULL if the dir index item does not exists, an error pointer if an
 301 * error happened, or a pointer to a dir item if the dir index item exists and
 302 * matches the criteria (name and index number).
 303 */
 304struct btrfs_dir_item *
 305btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
 306                            struct btrfs_root *root,
 307                            struct btrfs_path *path, u64 dir,
 308                            u64 index, const char *name, int name_len,
 309                            int mod)
 310{
 311        struct btrfs_dir_item *di;
 312        struct btrfs_key key;
 313
 314        key.objectid = dir;
 315        key.type = BTRFS_DIR_INDEX_KEY;
 316        key.offset = index;
 317
 318        di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
 319        if (di == ERR_PTR(-ENOENT))
 320                return NULL;
 321
 322        return di;
 323}
 324
 325struct btrfs_dir_item *
 326btrfs_search_dir_index_item(struct btrfs_root *root,
 327                            struct btrfs_path *path, u64 dirid,
 328                            const char *name, int name_len)
 329{
 330        struct extent_buffer *leaf;
 331        struct btrfs_dir_item *di;
 332        struct btrfs_key key;
 333        u32 nritems;
 334        int ret;
 335
 336        key.objectid = dirid;
 337        key.type = BTRFS_DIR_INDEX_KEY;
 338        key.offset = 0;
 339
 340        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 341        if (ret < 0)
 342                return ERR_PTR(ret);
 343
 344        leaf = path->nodes[0];
 345        nritems = btrfs_header_nritems(leaf);
 346
 347        while (1) {
 348                if (path->slots[0] >= nritems) {
 349                        ret = btrfs_next_leaf(root, path);
 350                        if (ret < 0)
 351                                return ERR_PTR(ret);
 352                        if (ret > 0)
 353                                break;
 354                        leaf = path->nodes[0];
 355                        nritems = btrfs_header_nritems(leaf);
 356                        continue;
 357                }
 358
 359                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 360                if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY)
 361                        break;
 362
 363                di = btrfs_match_dir_item_name(root->fs_info, path,
 364                                               name, name_len);
 365                if (di)
 366                        return di;
 367
 368                path->slots[0]++;
 369        }
 370        return NULL;
 371}
 372
 373struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
 374                                          struct btrfs_root *root,
 375                                          struct btrfs_path *path, u64 dir,
 376                                          const char *name, u16 name_len,
 377                                          int mod)
 378{
 379        struct btrfs_key key;
 380        struct btrfs_dir_item *di;
 381
 382        key.objectid = dir;
 383        key.type = BTRFS_XATTR_ITEM_KEY;
 384        key.offset = btrfs_name_hash(name, name_len);
 385
 386        di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
 387        if (IS_ERR(di) && PTR_ERR(di) == -ENOENT)
 388                return NULL;
 389
 390        return di;
 391}
 392
 393/*
 394 * helper function to look at the directory item pointed to by 'path'
 395 * this walks through all the entries in a dir item and finds one
 396 * for a specific name.
 397 */
 398struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
 399                                                 struct btrfs_path *path,
 400                                                 const char *name, int name_len)
 401{
 402        struct btrfs_dir_item *dir_item;
 403        unsigned long name_ptr;
 404        u32 total_len;
 405        u32 cur = 0;
 406        u32 this_len;
 407        struct extent_buffer *leaf;
 408
 409        leaf = path->nodes[0];
 410        dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
 411
 412        total_len = btrfs_item_size_nr(leaf, path->slots[0]);
 413        while (cur < total_len) {
 414                this_len = sizeof(*dir_item) +
 415                        btrfs_dir_name_len(leaf, dir_item) +
 416                        btrfs_dir_data_len(leaf, dir_item);
 417                name_ptr = (unsigned long)(dir_item + 1);
 418
 419                if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
 420                    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
 421                        return dir_item;
 422
 423                cur += this_len;
 424                dir_item = (struct btrfs_dir_item *)((char *)dir_item +
 425                                                     this_len);
 426        }
 427        return NULL;
 428}
 429
 430/*
 431 * given a pointer into a directory item, delete it.  This
 432 * handles items that have more than one entry in them.
 433 */
 434int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
 435                              struct btrfs_root *root,
 436                              struct btrfs_path *path,
 437                              struct btrfs_dir_item *di)
 438{
 439
 440        struct extent_buffer *leaf;
 441        u32 sub_item_len;
 442        u32 item_len;
 443        int ret = 0;
 444
 445        leaf = path->nodes[0];
 446        sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
 447                btrfs_dir_data_len(leaf, di);
 448        item_len = btrfs_item_size_nr(leaf, path->slots[0]);
 449        if (sub_item_len == item_len) {
 450                ret = btrfs_del_item(trans, root, path);
 451        } else {
 452                /* MARKER */
 453                unsigned long ptr = (unsigned long)di;
 454                unsigned long start;
 455
 456                start = btrfs_item_ptr_offset(leaf, path->slots[0]);
 457                memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
 458                        item_len - (ptr + sub_item_len - start));
 459                btrfs_truncate_item(path, item_len - sub_item_len, 1);
 460        }
 461        return ret;
 462}
 463