struct btrfs_root *root);
 
 /* dir-item.c */
+int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
+                         const char *name, int name_len);
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, const char *name,
                          int name_len, struct inode *dir,
 
        return btrfs_match_dir_item_name(root, path, name, name_len);
 }
 
+int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
+                                  const char *name, int name_len)
+{
+       int ret;
+       struct btrfs_key key;
+       struct btrfs_dir_item *di;
+       int data_size;
+       struct extent_buffer *leaf;
+       int slot;
+       struct btrfs_path *path;
+
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       key.objectid = dir;
+       btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
+       key.offset = btrfs_name_hash(name, name_len);
+
+       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+
+       /* return back any errors */
+       if (ret < 0)
+               goto out;
+
+       /* nothing found, we're safe */
+       if (ret > 0) {
+               ret = 0;
+               goto out;
+       }
+
+       /* we found an item, look for our name in the item */
+       di = btrfs_match_dir_item_name(root, path, name, name_len);
+       if (di) {
+               /* our exact name was found */
+               ret = -EEXIST;
+               goto out;
+       }
+
+       /*
+        * see if there is room in the item to insert this
+        * name
+        */
+       data_size = sizeof(*di) + name_len + sizeof(struct btrfs_item);
+       leaf = path->nodes[0];
+       slot = path->slots[0];
+       if (data_size + btrfs_item_size_nr(leaf, slot) +
+           sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root)) {
+               ret = -EOVERFLOW;
+       } else {
+               /* plenty of insertion room */
+               ret = 0;
+       }
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
 /*
  * lookup a directory item based on index.  'dir' is the objectid
  * we're searching in, and 'mod' tells us if you plan on deleting the
 
        ret = btrfs_insert_dir_item(trans, root, name, name_len,
                                    parent_inode, &key,
                                    btrfs_inode_type(inode), index);
-       if (ret == -EEXIST)
+       if (ret == -EEXIST || ret == -EOVERFLOW)
                goto fail_dir_item;
        else if (ret) {
                btrfs_abort_transaction(trans, root, ret);
        if (S_ISDIR(old_inode->i_mode) && new_inode &&
            new_inode->i_size > BTRFS_EMPTY_DIR_SIZE)
                return -ENOTEMPTY;
+
+
+       /* check for collisions, even if the  name isn't there */
+       ret = btrfs_check_dir_item_collision(root, new_dir->i_ino,
+                            new_dentry->d_name.name,
+                            new_dentry->d_name.len);
+
+       if (ret) {
+               if (ret == -EEXIST) {
+                       /* we shouldn't get
+                        * eexist without a new_inode */
+                       if (!new_inode) {
+                               WARN_ON(1);
+                               return ret;
+                       }
+               } else {
+                       /* maybe -EOVERFLOW */
+                       return ret;
+               }
+       }
+       ret = 0;
+
        /*
         * we're using rename to replace one file with another.
         * and the replacement file is large.  Start IO on it now so
 
        if (error)
                goto out_dput;
 
+       /*
+        * even if this name doesn't exist, we may get hash collisions.
+        * check for them now when we can safely fail
+        */
+       error = btrfs_check_dir_item_collision(BTRFS_I(dir)->root,
+                                              dir->i_ino, name,
+                                              namelen);
+       if (error)
+               goto out_dput;
+
        down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem);
 
        if (btrfs_root_refs(&BTRFS_I(dir)->root->root_item) == 0)
 
                                    parent_inode, &key,
                                    BTRFS_FT_DIR, index);
        /* We have check then name at the beginning, so it is impossible. */
-       BUG_ON(ret == -EEXIST);
+       BUG_ON(ret == -EEXIST || ret == -EOVERFLOW);
        if (ret) {
                btrfs_abort_transaction(trans, root, ret);
                goto fail;