LCOV - code coverage report
Current view: top level - fs/btrfs - dir-item.c (source / functions) Hit Total Coverage
Test: btrfstest.info Lines: 113 163 69.3 %
Date: 2014-11-28 Functions: 10 11 90.9 %

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

Generated by: LCOV version 1.10