Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2007 Oracle.  All rights reserved.
0004  */
0005 
0006 #include "ctree.h"
0007 #include "disk-io.h"
0008 #include "transaction.h"
0009 
0010 /*
0011  * insert a name into a directory, doing overflow properly if there is a hash
0012  * collision.  data_size indicates how big the item inserted should be.  On
0013  * success a struct btrfs_dir_item pointer is returned, otherwise it is
0014  * an ERR_PTR.
0015  *
0016  * The name is not copied into the dir item, you have to do that yourself.
0017  */
0018 static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
0019                            *trans,
0020                            struct btrfs_root *root,
0021                            struct btrfs_path *path,
0022                            struct btrfs_key *cpu_key,
0023                            u32 data_size,
0024                            const char *name,
0025                            int name_len)
0026 {
0027     struct btrfs_fs_info *fs_info = root->fs_info;
0028     int ret;
0029     char *ptr;
0030     struct extent_buffer *leaf;
0031 
0032     ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
0033     if (ret == -EEXIST) {
0034         struct btrfs_dir_item *di;
0035         di = btrfs_match_dir_item_name(fs_info, path, name, name_len);
0036         if (di)
0037             return ERR_PTR(-EEXIST);
0038         btrfs_extend_item(path, data_size);
0039     } else if (ret < 0)
0040         return ERR_PTR(ret);
0041     WARN_ON(ret > 0);
0042     leaf = path->nodes[0];
0043     ptr = btrfs_item_ptr(leaf, path->slots[0], char);
0044     ASSERT(data_size <= btrfs_item_size(leaf, path->slots[0]));
0045     ptr += btrfs_item_size(leaf, path->slots[0]) - data_size;
0046     return (struct btrfs_dir_item *)ptr;
0047 }
0048 
0049 /*
0050  * xattrs work a lot like directories, this inserts an xattr item
0051  * into the tree
0052  */
0053 int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
0054                 struct btrfs_root *root,
0055                 struct btrfs_path *path, u64 objectid,
0056                 const char *name, u16 name_len,
0057                 const void *data, u16 data_len)
0058 {
0059     int ret = 0;
0060     struct btrfs_dir_item *dir_item;
0061     unsigned long name_ptr, data_ptr;
0062     struct btrfs_key key, location;
0063     struct btrfs_disk_key disk_key;
0064     struct extent_buffer *leaf;
0065     u32 data_size;
0066 
0067     if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root->fs_info))
0068         return -ENOSPC;
0069 
0070     key.objectid = objectid;
0071     key.type = BTRFS_XATTR_ITEM_KEY;
0072     key.offset = btrfs_name_hash(name, name_len);
0073 
0074     data_size = sizeof(*dir_item) + name_len + data_len;
0075     dir_item = insert_with_overflow(trans, root, path, &key, data_size,
0076                     name, name_len);
0077     if (IS_ERR(dir_item))
0078         return PTR_ERR(dir_item);
0079     memset(&location, 0, sizeof(location));
0080 
0081     leaf = path->nodes[0];
0082     btrfs_cpu_key_to_disk(&disk_key, &location);
0083     btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
0084     btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
0085     btrfs_set_dir_name_len(leaf, dir_item, name_len);
0086     btrfs_set_dir_transid(leaf, dir_item, trans->transid);
0087     btrfs_set_dir_data_len(leaf, dir_item, data_len);
0088     name_ptr = (unsigned long)(dir_item + 1);
0089     data_ptr = (unsigned long)((char *)name_ptr + name_len);
0090 
0091     write_extent_buffer(leaf, name, name_ptr, name_len);
0092     write_extent_buffer(leaf, data, data_ptr, data_len);
0093     btrfs_mark_buffer_dirty(path->nodes[0]);
0094 
0095     return ret;
0096 }
0097 
0098 /*
0099  * insert a directory item in the tree, doing all the magic for
0100  * both indexes. 'dir' indicates which objectid to insert it into,
0101  * 'location' is the key to stuff into the directory item, 'type' is the
0102  * type of the inode we're pointing to, and 'index' is the sequence number
0103  * to use for the second index (if one is created).
0104  * Will return 0 or -ENOMEM
0105  */
0106 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name,
0107               int name_len, struct btrfs_inode *dir,
0108               struct btrfs_key *location, u8 type, u64 index)
0109 {
0110     int ret = 0;
0111     int ret2 = 0;
0112     struct btrfs_root *root = dir->root;
0113     struct btrfs_path *path;
0114     struct btrfs_dir_item *dir_item;
0115     struct extent_buffer *leaf;
0116     unsigned long name_ptr;
0117     struct btrfs_key key;
0118     struct btrfs_disk_key disk_key;
0119     u32 data_size;
0120 
0121     key.objectid = btrfs_ino(dir);
0122     key.type = BTRFS_DIR_ITEM_KEY;
0123     key.offset = btrfs_name_hash(name, name_len);
0124 
0125     path = btrfs_alloc_path();
0126     if (!path)
0127         return -ENOMEM;
0128 
0129     btrfs_cpu_key_to_disk(&disk_key, location);
0130 
0131     data_size = sizeof(*dir_item) + name_len;
0132     dir_item = insert_with_overflow(trans, root, path, &key, data_size,
0133                     name, name_len);
0134     if (IS_ERR(dir_item)) {
0135         ret = PTR_ERR(dir_item);
0136         if (ret == -EEXIST)
0137             goto second_insert;
0138         goto out_free;
0139     }
0140 
0141     leaf = path->nodes[0];
0142     btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
0143     btrfs_set_dir_type(leaf, dir_item, type);
0144     btrfs_set_dir_data_len(leaf, dir_item, 0);
0145     btrfs_set_dir_name_len(leaf, dir_item, name_len);
0146     btrfs_set_dir_transid(leaf, dir_item, trans->transid);
0147     name_ptr = (unsigned long)(dir_item + 1);
0148 
0149     write_extent_buffer(leaf, name, name_ptr, name_len);
0150     btrfs_mark_buffer_dirty(leaf);
0151 
0152 second_insert:
0153     /* FIXME, use some real flag for selecting the extra index */
0154     if (root == root->fs_info->tree_root) {
0155         ret = 0;
0156         goto out_free;
0157     }
0158     btrfs_release_path(path);
0159 
0160     ret2 = btrfs_insert_delayed_dir_index(trans, name, name_len, dir,
0161                           &disk_key, type, index);
0162 out_free:
0163     btrfs_free_path(path);
0164     if (ret)
0165         return ret;
0166     if (ret2)
0167         return ret2;
0168     return 0;
0169 }
0170 
0171 static struct btrfs_dir_item *btrfs_lookup_match_dir(
0172             struct btrfs_trans_handle *trans,
0173             struct btrfs_root *root, struct btrfs_path *path,
0174             struct btrfs_key *key, const char *name,
0175             int name_len, int mod)
0176 {
0177     const int ins_len = (mod < 0 ? -1 : 0);
0178     const int cow = (mod != 0);
0179     int ret;
0180 
0181     ret = btrfs_search_slot(trans, root, key, path, ins_len, cow);
0182     if (ret < 0)
0183         return ERR_PTR(ret);
0184     if (ret > 0)
0185         return ERR_PTR(-ENOENT);
0186 
0187     return btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
0188 }
0189 
0190 /*
0191  * Lookup for a directory item by name.
0192  *
0193  * @trans:  The transaction handle to use. Can be NULL if @mod is 0.
0194  * @root:   The root of the target tree.
0195  * @path:   Path to use for the search.
0196  * @dir:    The inode number (objectid) of the directory.
0197  * @name:   The name associated to the directory entry we are looking for.
0198  * @name_len:   The length of the name.
0199  * @mod:    Used to indicate if the tree search is meant for a read only
0200  *      lookup, for a modification lookup or for a deletion lookup, so
0201  *      its value should be 0, 1 or -1, respectively.
0202  *
0203  * Returns: NULL if the dir item does not exists, an error pointer if an error
0204  * happened, or a pointer to a dir item if a dir item exists for the given name.
0205  */
0206 struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
0207                          struct btrfs_root *root,
0208                          struct btrfs_path *path, u64 dir,
0209                          const char *name, int name_len,
0210                          int mod)
0211 {
0212     struct btrfs_key key;
0213     struct btrfs_dir_item *di;
0214 
0215     key.objectid = dir;
0216     key.type = BTRFS_DIR_ITEM_KEY;
0217     key.offset = btrfs_name_hash(name, name_len);
0218 
0219     di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
0220     if (IS_ERR(di) && PTR_ERR(di) == -ENOENT)
0221         return NULL;
0222 
0223     return di;
0224 }
0225 
0226 int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
0227                    const char *name, int name_len)
0228 {
0229     int ret;
0230     struct btrfs_key key;
0231     struct btrfs_dir_item *di;
0232     int data_size;
0233     struct extent_buffer *leaf;
0234     int slot;
0235     struct btrfs_path *path;
0236 
0237     path = btrfs_alloc_path();
0238     if (!path)
0239         return -ENOMEM;
0240 
0241     key.objectid = dir;
0242     key.type = BTRFS_DIR_ITEM_KEY;
0243     key.offset = btrfs_name_hash(name, name_len);
0244 
0245     di = btrfs_lookup_match_dir(NULL, root, path, &key, name, name_len, 0);
0246     if (IS_ERR(di)) {
0247         ret = PTR_ERR(di);
0248         /* Nothing found, we're safe */
0249         if (ret == -ENOENT) {
0250             ret = 0;
0251             goto out;
0252         }
0253 
0254         if (ret < 0)
0255             goto out;
0256     }
0257 
0258     /* we found an item, look for our name in the item */
0259     if (di) {
0260         /* our exact name was found */
0261         ret = -EEXIST;
0262         goto out;
0263     }
0264 
0265     /*
0266      * see if there is room in the item to insert this
0267      * name
0268      */
0269     data_size = sizeof(*di) + name_len;
0270     leaf = path->nodes[0];
0271     slot = path->slots[0];
0272     if (data_size + btrfs_item_size(leaf, slot) +
0273         sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
0274         ret = -EOVERFLOW;
0275     } else {
0276         /* plenty of insertion room */
0277         ret = 0;
0278     }
0279 out:
0280     btrfs_free_path(path);
0281     return ret;
0282 }
0283 
0284 /*
0285  * Lookup for a directory index item by name and index number.
0286  *
0287  * @trans:  The transaction handle to use. Can be NULL if @mod is 0.
0288  * @root:   The root of the target tree.
0289  * @path:   Path to use for the search.
0290  * @dir:    The inode number (objectid) of the directory.
0291  * @index:  The index number.
0292  * @name:   The name associated to the directory entry we are looking for.
0293  * @name_len:   The length of the name.
0294  * @mod:    Used to indicate if the tree search is meant for a read only
0295  *      lookup, for a modification lookup or for a deletion lookup, so
0296  *      its value should be 0, 1 or -1, respectively.
0297  *
0298  * Returns: NULL if the dir index item does not exists, an error pointer if an
0299  * error happened, or a pointer to a dir item if the dir index item exists and
0300  * matches the criteria (name and index number).
0301  */
0302 struct btrfs_dir_item *
0303 btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
0304                 struct btrfs_root *root,
0305                 struct btrfs_path *path, u64 dir,
0306                 u64 index, const char *name, int name_len,
0307                 int mod)
0308 {
0309     struct btrfs_dir_item *di;
0310     struct btrfs_key key;
0311 
0312     key.objectid = dir;
0313     key.type = BTRFS_DIR_INDEX_KEY;
0314     key.offset = index;
0315 
0316     di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
0317     if (di == ERR_PTR(-ENOENT))
0318         return NULL;
0319 
0320     return di;
0321 }
0322 
0323 struct btrfs_dir_item *
0324 btrfs_search_dir_index_item(struct btrfs_root *root,
0325                 struct btrfs_path *path, u64 dirid,
0326                 const char *name, int name_len)
0327 {
0328     struct btrfs_dir_item *di;
0329     struct btrfs_key key;
0330     int ret;
0331 
0332     key.objectid = dirid;
0333     key.type = BTRFS_DIR_INDEX_KEY;
0334     key.offset = 0;
0335 
0336     btrfs_for_each_slot(root, &key, &key, path, ret) {
0337         if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY)
0338             break;
0339 
0340         di = btrfs_match_dir_item_name(root->fs_info, path,
0341                            name, name_len);
0342         if (di)
0343             return di;
0344     }
0345     /* Adjust return code if the key was not found in the next leaf. */
0346     if (ret > 0)
0347         ret = 0;
0348 
0349     return ERR_PTR(ret);
0350 }
0351 
0352 struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
0353                       struct btrfs_root *root,
0354                       struct btrfs_path *path, u64 dir,
0355                       const char *name, u16 name_len,
0356                       int mod)
0357 {
0358     struct btrfs_key key;
0359     struct btrfs_dir_item *di;
0360 
0361     key.objectid = dir;
0362     key.type = BTRFS_XATTR_ITEM_KEY;
0363     key.offset = btrfs_name_hash(name, name_len);
0364 
0365     di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
0366     if (IS_ERR(di) && PTR_ERR(di) == -ENOENT)
0367         return NULL;
0368 
0369     return di;
0370 }
0371 
0372 /*
0373  * helper function to look at the directory item pointed to by 'path'
0374  * this walks through all the entries in a dir item and finds one
0375  * for a specific name.
0376  */
0377 struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
0378                          struct btrfs_path *path,
0379                          const char *name, int name_len)
0380 {
0381     struct btrfs_dir_item *dir_item;
0382     unsigned long name_ptr;
0383     u32 total_len;
0384     u32 cur = 0;
0385     u32 this_len;
0386     struct extent_buffer *leaf;
0387 
0388     leaf = path->nodes[0];
0389     dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
0390 
0391     total_len = btrfs_item_size(leaf, path->slots[0]);
0392     while (cur < total_len) {
0393         this_len = sizeof(*dir_item) +
0394             btrfs_dir_name_len(leaf, dir_item) +
0395             btrfs_dir_data_len(leaf, dir_item);
0396         name_ptr = (unsigned long)(dir_item + 1);
0397 
0398         if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
0399             memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
0400             return dir_item;
0401 
0402         cur += this_len;
0403         dir_item = (struct btrfs_dir_item *)((char *)dir_item +
0404                              this_len);
0405     }
0406     return NULL;
0407 }
0408 
0409 /*
0410  * given a pointer into a directory item, delete it.  This
0411  * handles items that have more than one entry in them.
0412  */
0413 int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
0414                   struct btrfs_root *root,
0415                   struct btrfs_path *path,
0416                   struct btrfs_dir_item *di)
0417 {
0418 
0419     struct extent_buffer *leaf;
0420     u32 sub_item_len;
0421     u32 item_len;
0422     int ret = 0;
0423 
0424     leaf = path->nodes[0];
0425     sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
0426         btrfs_dir_data_len(leaf, di);
0427     item_len = btrfs_item_size(leaf, path->slots[0]);
0428     if (sub_item_len == item_len) {
0429         ret = btrfs_del_item(trans, root, path);
0430     } else {
0431         /* MARKER */
0432         unsigned long ptr = (unsigned long)di;
0433         unsigned long start;
0434 
0435         start = btrfs_item_ptr_offset(leaf, path->slots[0]);
0436         memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
0437             item_len - (ptr + sub_item_len - start));
0438         btrfs_truncate_item(path, item_len - sub_item_len, 1);
0439     }
0440     return ret;
0441 }