OSDN Git Service

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 4 Jun 2011 21:17:23 +0000 (06:17 +0900)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 4 Jun 2011 21:17:23 +0000 (06:17 +0900)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: (25 commits)
  btrfs: fix uninitialized variable warning
  btrfs: add helper for fs_info->closing
  Btrfs: add mount -o inode_cache
  btrfs: scrub: add explicit plugging
  btrfs: use btrfs_ino to access inode number
  Btrfs: don't save the inode cache if we are deleting this root
  btrfs: false BUG_ON when degraded
  Btrfs: don't save the inode cache in non-FS roots
  Btrfs: make sure we don't overflow the free space cache crc page
  Btrfs: fix uninit variable in the delayed inode code
  btrfs: scrub: don't reuse bios and pages
  Btrfs: leave spinning on lookup and map the leaf
  Btrfs: check for duplicate entries in the free space cache
  Btrfs: don't try to allocate from a block group that doesn't have enough space
  Btrfs: don't always do readahead
  Btrfs: try not to sleep as much when doing slow caching
  Btrfs: kill BTRFS_I(inode)->block_group
  Btrfs: don't look at the extent buffer level 3 times in a row
  Btrfs: map the node block when looking for readahead targets
  Btrfs: set range_start to the right start in count_range_bits
  ...

1  2 
fs/btrfs/ctree.h
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/relocation.c
fs/btrfs/super.c

diff --combined fs/btrfs/ctree.h
@@@ -930,7 -930,6 +930,6 @@@ struct btrfs_fs_info 
         * is required instead of the faster short fsync log commits
         */
        u64 last_trans_log_full_commit;
-       u64 open_ioctl_trans;
        unsigned long mount_opt:20;
        unsigned long compress_type:4;
        u64 max_inline;
        struct super_block *sb;
        struct inode *btree_inode;
        struct backing_dev_info bdi;
-       struct mutex trans_mutex;
        struct mutex tree_log_mutex;
        struct mutex transaction_kthread_mutex;
        struct mutex cleaner_mutex;
        struct rw_semaphore subvol_sem;
        struct srcu_struct subvol_srcu;
  
+       spinlock_t trans_lock;
        struct list_head trans_list;
        struct list_head hashers;
        struct list_head dead_roots;
        atomic_t async_submit_draining;
        atomic_t nr_async_bios;
        atomic_t async_delalloc_pages;
+       atomic_t open_ioctl_trans;
  
        /*
         * this is used by the balancing code to wait for all the pending
        int closing;
        int log_root_recovering;
        int enospc_unlink;
+       int trans_no_join;
  
        u64 total_pinned;
  
        struct reloc_control *reloc_ctl;
  
        spinlock_t delalloc_lock;
-       spinlock_t new_trans_lock;
        u64 delalloc_bytes;
  
        /* data_alloc_cluster is only used in ssd mode */
@@@ -1340,6 -1340,7 +1340,7 @@@ struct btrfs_ioctl_defrag_range_args 
  #define BTRFS_MOUNT_USER_SUBVOL_RM_ALLOWED (1 << 14)
  #define BTRFS_MOUNT_ENOSPC_DEBUG       (1 << 15)
  #define BTRFS_MOUNT_AUTO_DEFRAG               (1 << 16)
+ #define BTRFS_MOUNT_INODE_MAP_CACHE   (1 << 17)
  
  #define btrfs_clear_opt(o, opt)               ((o) &= ~BTRFS_MOUNT_##opt)
  #define btrfs_set_opt(o, opt)         ((o) |= BTRFS_MOUNT_##opt)
@@@ -2238,6 -2239,9 +2239,9 @@@ int btrfs_block_rsv_migrate(struct btrf
  void btrfs_block_rsv_release(struct btrfs_root *root,
                             struct btrfs_block_rsv *block_rsv,
                             u64 num_bytes);
+ int btrfs_truncate_reserve_metadata(struct btrfs_trans_handle *trans,
+                                   struct btrfs_root *root,
+                                   struct btrfs_block_rsv *rsv);
  int btrfs_set_block_group_ro(struct btrfs_root *root,
                             struct btrfs_block_group_cache *cache);
  int btrfs_set_block_group_rw(struct btrfs_root *root,
@@@ -2350,6 -2354,15 +2354,15 @@@ int btrfs_drop_subtree(struct btrfs_tra
                        struct btrfs_root *root,
                        struct extent_buffer *node,
                        struct extent_buffer *parent);
+ static inline int btrfs_fs_closing(struct btrfs_fs_info *fs_info)
+ {
+       /*
+        * Get synced with close_ctree()
+        */
+       smp_mb();
+       return fs_info->closing;
+ }
  /* root-item.c */
  int btrfs_find_root_ref(struct btrfs_root *tree_root,
                        struct btrfs_path *path,
@@@ -2512,8 -2525,7 +2525,7 @@@ int btrfs_set_extent_delalloc(struct in
  int btrfs_writepages(struct address_space *mapping,
                     struct writeback_control *wbc);
  int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
-                            struct btrfs_root *new_root,
-                            u64 new_dirid, u64 alloc_hint);
+                            struct btrfs_root *new_root, u64 new_dirid);
  int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
                         size_t size, struct bio *bio, unsigned long bio_flags);
  
@@@ -2524,7 -2536,7 +2536,7 @@@ int btrfs_page_mkwrite(struct vm_area_s
  int btrfs_readpage(struct file *file, struct page *page);
  void btrfs_evict_inode(struct inode *inode);
  int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc);
 -void btrfs_dirty_inode(struct inode *inode);
 +void btrfs_dirty_inode(struct inode *inode, int flags);
  struct inode *btrfs_alloc_inode(struct super_block *sb);
  void btrfs_destroy_inode(struct inode *inode);
  int btrfs_drop_inode(struct inode *inode);
diff --combined fs/btrfs/extent_io.c
@@@ -10,8 -10,6 +10,8 @@@
  #include <linux/swap.h>
  #include <linux/writeback.h>
  #include <linux/pagevec.h>
 +#include <linux/prefetch.h>
 +#include <linux/cleancache.h>
  #include "extent_io.h"
  #include "extent_map.h"
  #include "compat.h"
@@@ -1476,7 -1474,7 +1476,7 @@@ u64 count_range_bits(struct extent_io_t
                        if (total_bytes >= max_bytes)
                                break;
                        if (!found) {
-                               *start = state->start;
+                               *start = max(cur_start, state->start);
                                found = 1;
                        }
                        last = state->end;
@@@ -1971,13 -1969,6 +1971,13 @@@ static int __extent_read_full_page(stru
  
        set_page_extent_mapped(page);
  
 +      if (!PageUptodate(page)) {
 +              if (cleancache_get_page(page) == 0) {
 +                      BUG_ON(blocksize != PAGE_SIZE);
 +                      goto out;
 +              }
 +      }
 +
        end = page_end;
        while (1) {
                lock_extent(tree, start, end, GFP_NOFS);
                cur = cur + iosize;
                pg_offset += iosize;
        }
 +out:
        if (!nr) {
                if (!PageError(page))
                        SetPageUptodate(page);
diff --combined fs/btrfs/inode.c
@@@ -138,7 -138,6 +138,6 @@@ static noinline int insert_inline_exten
                return -ENOMEM;
  
        path->leave_spinning = 1;
-       btrfs_set_trans_block_group(trans, inode);
  
        key.objectid = btrfs_ino(inode);
        key.offset = start;
@@@ -426,9 -425,8 +425,8 @@@ again
                }
        }
        if (start == 0) {
-               trans = btrfs_join_transaction(root, 1);
+               trans = btrfs_join_transaction(root);
                BUG_ON(IS_ERR(trans));
-               btrfs_set_trans_block_group(trans, inode);
                trans->block_rsv = &root->fs_info->delalloc_block_rsv;
  
                /* lets try to make an inline extent */
@@@ -623,8 -621,9 +621,9 @@@ retry
                            async_extent->start + async_extent->ram_size - 1,
                            GFP_NOFS);
  
-               trans = btrfs_join_transaction(root, 1);
+               trans = btrfs_join_transaction(root);
                BUG_ON(IS_ERR(trans));
+               trans->block_rsv = &root->fs_info->delalloc_block_rsv;
                ret = btrfs_reserve_extent(trans, root,
                                           async_extent->compressed_size,
                                           async_extent->compressed_size,
@@@ -793,9 -792,8 +792,8 @@@ static noinline int cow_file_range(stru
        int ret = 0;
  
        BUG_ON(is_free_space_inode(root, inode));
-       trans = btrfs_join_transaction(root, 1);
+       trans = btrfs_join_transaction(root);
        BUG_ON(IS_ERR(trans));
-       btrfs_set_trans_block_group(trans, inode);
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
  
        num_bytes = (end - start + blocksize) & ~(blocksize - 1);
@@@ -1077,10 -1075,12 +1075,12 @@@ static noinline int run_delalloc_nocow(
        nolock = is_free_space_inode(root, inode);
  
        if (nolock)
-               trans = btrfs_join_transaction_nolock(root, 1);
+               trans = btrfs_join_transaction_nolock(root);
        else
-               trans = btrfs_join_transaction(root, 1);
+               trans = btrfs_join_transaction(root);
        BUG_ON(IS_ERR(trans));
+       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
  
        cow_start = (u64)-1;
        cur_offset = start;
@@@ -1519,8 -1519,6 +1519,6 @@@ static noinline int add_pending_csums(s
  {
        struct btrfs_ordered_sum *sum;
  
-       btrfs_set_trans_block_group(trans, inode);
        list_for_each_entry(sum, list, list) {
                btrfs_csum_file_blocks(trans,
                       BTRFS_I(inode)->root->fs_info->csum_root, sum);
@@@ -1735,11 -1733,10 +1733,10 @@@ static int btrfs_finish_ordered_io(stru
                ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
                if (!ret) {
                        if (nolock)
-                               trans = btrfs_join_transaction_nolock(root, 1);
+                               trans = btrfs_join_transaction_nolock(root);
                        else
-                               trans = btrfs_join_transaction(root, 1);
+                               trans = btrfs_join_transaction(root);
                        BUG_ON(IS_ERR(trans));
-                       btrfs_set_trans_block_group(trans, inode);
                        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
                        ret = btrfs_update_inode(trans, root, inode);
                        BUG_ON(ret);
                         0, &cached_state, GFP_NOFS);
  
        if (nolock)
-               trans = btrfs_join_transaction_nolock(root, 1);
+               trans = btrfs_join_transaction_nolock(root);
        else
-               trans = btrfs_join_transaction(root, 1);
+               trans = btrfs_join_transaction(root);
        BUG_ON(IS_ERR(trans));
-       btrfs_set_trans_block_group(trans, inode);
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
  
        if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags))
@@@ -2431,7 -2427,7 +2427,7 @@@ int btrfs_orphan_cleanup(struct btrfs_r
                                        (u64)-1);
  
        if (root->orphan_block_rsv || root->orphan_item_inserted) {
-               trans = btrfs_join_transaction(root, 1);
+               trans = btrfs_join_transaction(root);
                if (!IS_ERR(trans))
                        btrfs_end_transaction(trans, root);
        }
@@@ -2511,12 -2507,12 +2507,12 @@@ static void btrfs_read_locked_inode(str
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_key location;
        int maybe_acls;
-       u64 alloc_group_block;
        u32 rdev;
        int ret;
  
        path = btrfs_alloc_path();
        BUG_ON(!path);
+       path->leave_spinning = 1;
        memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
  
        ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
        leaf = path->nodes[0];
        inode_item = btrfs_item_ptr(leaf, path->slots[0],
                                    struct btrfs_inode_item);
+       if (!leaf->map_token)
+               map_private_extent_buffer(leaf, (unsigned long)inode_item,
+                                         sizeof(struct btrfs_inode_item),
+                                         &leaf->map_token, &leaf->kaddr,
+                                         &leaf->map_start, &leaf->map_len,
+                                         KM_USER1);
  
        inode->i_mode = btrfs_inode_mode(leaf, inode_item);
        inode->i_nlink = btrfs_inode_nlink(leaf, inode_item);
        BTRFS_I(inode)->index_cnt = (u64)-1;
        BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
  
-       alloc_group_block = btrfs_inode_block_group(leaf, inode_item);
        /*
         * try to precache a NULL acl entry for files that don't have
         * any xattrs or acls
        if (!maybe_acls)
                cache_no_acl(inode);
  
-       BTRFS_I(inode)->block_group = btrfs_find_block_group(root, 0,
-                                               alloc_group_block, 0);
+       if (leaf->map_token) {
+               unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
+               leaf->map_token = NULL;
+       }
        btrfs_free_path(path);
        inode_item = NULL;
  
@@@ -2647,7 -2650,7 +2650,7 @@@ static void fill_inode_item(struct btrf
        btrfs_set_inode_transid(leaf, item, trans->transid);
        btrfs_set_inode_rdev(leaf, item, inode->i_rdev);
        btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags);
-       btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group);
+       btrfs_set_inode_block_group(leaf, item, 0);
  
        if (leaf->map_token) {
                unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
@@@ -3004,8 -3007,6 +3007,6 @@@ static int btrfs_unlink(struct inode *d
        if (IS_ERR(trans))
                return PTR_ERR(trans);
  
-       btrfs_set_trans_block_group(trans, dir);
        btrfs_record_unlink_dir(trans, dir, dentry->d_inode, 0);
  
        ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode,
@@@ -3094,8 -3095,6 +3095,6 @@@ static int btrfs_rmdir(struct inode *di
        if (IS_ERR(trans))
                return PTR_ERR(trans);
  
-       btrfs_set_trans_block_group(trans, dir);
        if (unlikely(btrfs_ino(inode) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
                err = btrfs_unlink_subvol(trans, root, dir,
                                          BTRFS_I(inode)->location.objectid,
@@@ -3514,7 -3513,6 +3513,6 @@@ int btrfs_cont_expand(struct inode *ino
                                err = PTR_ERR(trans);
                                break;
                        }
-                       btrfs_set_trans_block_group(trans, inode);
  
                        err = btrfs_drop_extents(trans, inode, cur_offset,
                                                 cur_offset + hole_size,
@@@ -3650,7 -3648,6 +3648,6 @@@ void btrfs_evict_inode(struct inode *in
        while (1) {
                trans = btrfs_start_transaction(root, 0);
                BUG_ON(IS_ERR(trans));
-               btrfs_set_trans_block_group(trans, inode);
                trans->block_rsv = root->orphan_block_rsv;
  
                ret = btrfs_block_rsv_check(trans, root,
@@@ -4133,7 -4130,8 +4130,8 @@@ static int btrfs_real_readdir(struct fi
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
-       path->reada = 2;
+       path->reada = 1;
  
        if (key_type == BTRFS_DIR_INDEX_KEY) {
                INIT_LIST_HEAD(&ins_list);
@@@ -4268,18 -4266,16 +4266,16 @@@ int btrfs_write_inode(struct inode *ino
        if (BTRFS_I(inode)->dummy_inode)
                return 0;
  
-       smp_mb();
-       if (root->fs_info->closing && is_free_space_inode(root, inode))
+       if (btrfs_fs_closing(root->fs_info) && is_free_space_inode(root, inode))
                nolock = true;
  
        if (wbc->sync_mode == WB_SYNC_ALL) {
                if (nolock)
-                       trans = btrfs_join_transaction_nolock(root, 1);
+                       trans = btrfs_join_transaction_nolock(root);
                else
-                       trans = btrfs_join_transaction(root, 1);
+                       trans = btrfs_join_transaction(root);
                if (IS_ERR(trans))
                        return PTR_ERR(trans);
-               btrfs_set_trans_block_group(trans, inode);
                if (nolock)
                        ret = btrfs_end_transaction_nolock(trans, root);
                else
   * FIXME, needs more benchmarking...there are no reasons other than performance
   * to keep or drop this code.
   */
 -void btrfs_dirty_inode(struct inode *inode)
 +void btrfs_dirty_inode(struct inode *inode, int flags)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
        if (BTRFS_I(inode)->dummy_inode)
                return;
  
-       trans = btrfs_join_transaction(root, 1);
+       trans = btrfs_join_transaction(root);
        BUG_ON(IS_ERR(trans));
-       btrfs_set_trans_block_group(trans, inode);
  
        ret = btrfs_update_inode(trans, root, inode);
        if (ret && ret == -ENOSPC) {
                                       PTR_ERR(trans));
                        return;
                }
-               btrfs_set_trans_block_group(trans, inode);
  
                ret = btrfs_update_inode(trans, root, inode);
                if (ret) {
@@@ -4418,8 -4412,8 +4412,8 @@@ static struct inode *btrfs_new_inode(st
                                     struct btrfs_root *root,
                                     struct inode *dir,
                                     const char *name, int name_len,
-                                    u64 ref_objectid, u64 objectid,
-                                    u64 alloc_hint, int mode, u64 *index)
+                                    u64 ref_objectid, u64 objectid, int mode,
+                                    u64 *index)
  {
        struct inode *inode;
        struct btrfs_inode_item *inode_item;
                owner = 0;
        else
                owner = 1;
-       BTRFS_I(inode)->block_group =
-                       btrfs_find_block_group(root, 0, alloc_hint, owner);
  
        key[0].objectid = objectid;
        btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY);
@@@ -4629,15 -4621,13 +4621,13 @@@ static int btrfs_mknod(struct inode *di
        if (IS_ERR(trans))
                return PTR_ERR(trans);
  
-       btrfs_set_trans_block_group(trans, dir);
        err = btrfs_find_free_ino(root, &objectid);
        if (err)
                goto out_unlock;
  
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len, btrfs_ino(dir), objectid,
-                               BTRFS_I(dir)->block_group, mode, &index);
+                               mode, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto out_unlock;
                goto out_unlock;
        }
  
-       btrfs_set_trans_block_group(trans, inode);
        err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
        if (err)
                drop_inode = 1;
                init_special_inode(inode, inode->i_mode, rdev);
                btrfs_update_inode(trans, root, inode);
        }
-       btrfs_update_inode_block_group(trans, inode);
-       btrfs_update_inode_block_group(trans, dir);
  out_unlock:
        nr = trans->blocks_used;
        btrfs_end_transaction_throttle(trans, root);
@@@ -4692,15 -4679,13 +4679,13 @@@ static int btrfs_create(struct inode *d
        if (IS_ERR(trans))
                return PTR_ERR(trans);
  
-       btrfs_set_trans_block_group(trans, dir);
        err = btrfs_find_free_ino(root, &objectid);
        if (err)
                goto out_unlock;
  
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len, btrfs_ino(dir), objectid,
-                               BTRFS_I(dir)->block_group, mode, &index);
+                               mode, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto out_unlock;
                goto out_unlock;
        }
  
-       btrfs_set_trans_block_group(trans, inode);
        err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
        if (err)
                drop_inode = 1;
                inode->i_op = &btrfs_file_inode_operations;
                BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
        }
-       btrfs_update_inode_block_group(trans, inode);
-       btrfs_update_inode_block_group(trans, dir);
  out_unlock:
        nr = trans->blocks_used;
        btrfs_end_transaction_throttle(trans, root);
@@@ -4771,8 -4753,6 +4753,6 @@@ static int btrfs_link(struct dentry *ol
  
        btrfs_inc_nlink(inode);
        inode->i_ctime = CURRENT_TIME;
-       btrfs_set_trans_block_group(trans, dir);
        ihold(inode);
  
        err = btrfs_add_nondir(trans, dir, dentry, inode, 1, index);
                drop_inode = 1;
        } else {
                struct dentry *parent = dget_parent(dentry);
-               btrfs_update_inode_block_group(trans, dir);
                err = btrfs_update_inode(trans, root, inode);
                BUG_ON(err);
                btrfs_log_new_name(trans, inode, NULL, parent);
@@@ -4818,7 -4797,6 +4797,6 @@@ static int btrfs_mkdir(struct inode *di
        trans = btrfs_start_transaction(root, 5);
        if (IS_ERR(trans))
                return PTR_ERR(trans);
-       btrfs_set_trans_block_group(trans, dir);
  
        err = btrfs_find_free_ino(root, &objectid);
        if (err)
  
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len, btrfs_ino(dir), objectid,
-                               BTRFS_I(dir)->block_group, S_IFDIR | mode,
-                               &index);
+                               S_IFDIR | mode, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto out_fail;
  
        inode->i_op = &btrfs_dir_inode_operations;
        inode->i_fop = &btrfs_dir_file_operations;
-       btrfs_set_trans_block_group(trans, inode);
  
        btrfs_i_size_write(inode, 0);
        err = btrfs_update_inode(trans, root, inode);
  
        d_instantiate(dentry, inode);
        drop_on_err = 0;
-       btrfs_update_inode_block_group(trans, inode);
-       btrfs_update_inode_block_group(trans, dir);
  
  out_fail:
        nr = trans->blocks_used;
@@@ -4989,7 -4963,15 +4963,15 @@@ again
  
        if (!path) {
                path = btrfs_alloc_path();
-               BUG_ON(!path);
+               if (!path) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+               /*
+                * Chances are we'll be called again, so go ahead and do
+                * readahead
+                */
+               path->reada = 1;
        }
  
        ret = btrfs_lookup_file_extent(trans, root, path,
                                kunmap(page);
                                free_extent_map(em);
                                em = NULL;
                                btrfs_release_path(path);
-                               trans = btrfs_join_transaction(root, 1);
+                               trans = btrfs_join_transaction(root);
                                if (IS_ERR(trans))
                                        return ERR_CAST(trans);
                                goto again;
@@@ -5375,7 -5359,7 +5359,7 @@@ static struct extent_map *btrfs_new_ext
                btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
        }
  
-       trans = btrfs_join_transaction(root, 0);
+       trans = btrfs_join_transaction(root);
        if (IS_ERR(trans))
                return ERR_CAST(trans);
  
@@@ -5611,7 -5595,7 +5595,7 @@@ static int btrfs_get_blocks_direct(stru
                 * to make sure the current transaction stays open
                 * while we look for nocow cross refs
                 */
-               trans = btrfs_join_transaction(root, 0);
+               trans = btrfs_join_transaction(root);
                if (IS_ERR(trans))
                        goto must_cow;
  
@@@ -5750,7 -5734,7 +5734,7 @@@ again
  
        BUG_ON(!ordered);
  
-       trans = btrfs_join_transaction(root, 1);
+       trans = btrfs_join_transaction(root);
        if (IS_ERR(trans)) {
                err = -ENOMEM;
                goto out;
@@@ -6500,6 -6484,7 +6484,7 @@@ out
  static int btrfs_truncate(struct inode *inode)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_block_rsv *rsv;
        int ret;
        int err = 0;
        struct btrfs_trans_handle *trans;
        btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
        btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
  
-       trans = btrfs_start_transaction(root, 5);
-       if (IS_ERR(trans))
-               return PTR_ERR(trans);
+       /*
+        * Yes ladies and gentelment, this is indeed ugly.  The fact is we have
+        * 3 things going on here
+        *
+        * 1) We need to reserve space for our orphan item and the space to
+        * delete our orphan item.  Lord knows we don't want to have a dangling
+        * orphan item because we didn't reserve space to remove it.
+        *
+        * 2) We need to reserve space to update our inode.
+        *
+        * 3) We need to have something to cache all the space that is going to
+        * be free'd up by the truncate operation, but also have some slack
+        * space reserved in case it uses space during the truncate (thank you
+        * very much snapshotting).
+        *
+        * And we need these to all be seperate.  The fact is we can use alot of
+        * space doing the truncate, and we have no earthly idea how much space
+        * we will use, so we need the truncate reservation to be seperate so it
+        * doesn't end up using space reserved for updating the inode or
+        * removing the orphan item.  We also need to be able to stop the
+        * transaction and start a new one, which means we need to be able to
+        * update the inode several times, and we have no idea of knowing how
+        * many times that will be, so we can't just reserve 1 item for the
+        * entirety of the opration, so that has to be done seperately as well.
+        * Then there is the orphan item, which does indeed need to be held on
+        * to for the whole operation, and we need nobody to touch this reserved
+        * space except the orphan code.
+        *
+        * So that leaves us with
+        *
+        * 1) root->orphan_block_rsv - for the orphan deletion.
+        * 2) rsv - for the truncate reservation, which we will steal from the
+        * transaction reservation.
+        * 3) fs_info->trans_block_rsv - this will have 1 items worth left for
+        * updating the inode.
+        */
+       rsv = btrfs_alloc_block_rsv(root);
+       if (!rsv)
+               return -ENOMEM;
+       btrfs_add_durable_block_rsv(root->fs_info, rsv);
  
-       btrfs_set_trans_block_group(trans, inode);
+       trans = btrfs_start_transaction(root, 4);
+       if (IS_ERR(trans)) {
+               err = PTR_ERR(trans);
+               goto out;
+       }
+       /*
+        * Reserve space for the truncate process.  Truncate should be adding
+        * space, but if there are snapshots it may end up using space.
+        */
+       ret = btrfs_truncate_reserve_metadata(trans, root, rsv);
+       BUG_ON(ret);
  
        ret = btrfs_orphan_add(trans, inode);
        if (ret) {
                btrfs_end_transaction(trans, root);
-               return ret;
+               goto out;
        }
  
        nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty(root, nr);
  
-       /* Now start a transaction for the truncate */
-       trans = btrfs_start_transaction(root, 0);
-       if (IS_ERR(trans))
-               return PTR_ERR(trans);
-       btrfs_set_trans_block_group(trans, inode);
-       trans->block_rsv = root->orphan_block_rsv;
+       /*
+        * Ok so we've already migrated our bytes over for the truncate, so here
+        * just reserve the one slot we need for updating the inode.
+        */
+       trans = btrfs_start_transaction(root, 1);
+       if (IS_ERR(trans)) {
+               err = PTR_ERR(trans);
+               goto out;
+       }
+       trans->block_rsv = rsv;
  
        /*
         * setattr is responsible for setting the ordered_data_close flag,
  
        while (1) {
                if (!trans) {
-                       trans = btrfs_start_transaction(root, 0);
-                       if (IS_ERR(trans))
-                               return PTR_ERR(trans);
-                       btrfs_set_trans_block_group(trans, inode);
-                       trans->block_rsv = root->orphan_block_rsv;
-               }
+                       trans = btrfs_start_transaction(root, 3);
+                       if (IS_ERR(trans)) {
+                               err = PTR_ERR(trans);
+                               goto out;
+                       }
  
-               ret = btrfs_block_rsv_check(trans, root,
-                                           root->orphan_block_rsv, 0, 5);
-               if (ret == -EAGAIN) {
-                       ret = btrfs_commit_transaction(trans, root);
-                       if (ret)
-                               return ret;
-                       trans = NULL;
-                       continue;
-               } else if (ret) {
-                       err = ret;
-                       break;
+                       ret = btrfs_truncate_reserve_metadata(trans, root,
+                                                             rsv);
+                       BUG_ON(ret);
+                       trans->block_rsv = rsv;
                }
  
                ret = btrfs_truncate_inode_items(trans, root, inode,
                        break;
                }
  
+               trans->block_rsv = &root->fs_info->trans_block_rsv;
                ret = btrfs_update_inode(trans, root, inode);
                if (ret) {
                        err = ret;
        }
  
        if (ret == 0 && inode->i_nlink > 0) {
+               trans->block_rsv = root->orphan_block_rsv;
                ret = btrfs_orphan_del(trans, inode);
                if (ret)
                        err = ret;
                ret = btrfs_orphan_del(NULL, inode);
        }
  
+       trans->block_rsv = &root->fs_info->trans_block_rsv;
        ret = btrfs_update_inode(trans, root, inode);
        if (ret && !err)
                err = ret;
  
        nr = trans->blocks_used;
        ret = btrfs_end_transaction_throttle(trans, root);
+       btrfs_btree_balance_dirty(root, nr);
+ out:
+       btrfs_free_block_rsv(root, rsv);
        if (ret && !err)
                err = ret;
-       btrfs_btree_balance_dirty(root, nr);
  
        return err;
  }
   * create a new subvolume directory/inode (helper for the ioctl).
   */
  int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
-                            struct btrfs_root *new_root,
-                            u64 new_dirid, u64 alloc_hint)
+                            struct btrfs_root *new_root, u64 new_dirid)
  {
        struct inode *inode;
        int err;
        u64 index = 0;
  
        inode = btrfs_new_inode(trans, new_root, NULL, "..", 2, new_dirid,
-                               new_dirid, alloc_hint, S_IFDIR | 0700, &index);
+                               new_dirid, S_IFDIR | 0700, &index);
        if (IS_ERR(inode))
                return PTR_ERR(inode);
        inode->i_op = &btrfs_dir_inode_operations;
@@@ -6748,21 -6784,6 +6784,6 @@@ void btrfs_destroy_inode(struct inode *
                spin_unlock(&root->fs_info->ordered_extent_lock);
        }
  
-       if (root == root->fs_info->tree_root) {
-               struct btrfs_block_group_cache *block_group;
-               block_group = btrfs_lookup_block_group(root->fs_info,
-                                               BTRFS_I(inode)->block_group);
-               if (block_group && block_group->inode == inode) {
-                       spin_lock(&block_group->lock);
-                       block_group->inode = NULL;
-                       spin_unlock(&block_group->lock);
-                       btrfs_put_block_group(block_group);
-               } else if (block_group) {
-                       btrfs_put_block_group(block_group);
-               }
-       }
        spin_lock(&root->orphan_lock);
        if (!list_empty(&BTRFS_I(inode)->i_orphan)) {
                printk(KERN_INFO "BTRFS: inode %llu still on the orphan list\n",
@@@ -6948,8 -6969,6 +6969,6 @@@ static int btrfs_rename(struct inode *o
                  goto out_notrans;
          }
  
-       btrfs_set_trans_block_group(trans, new_dir);
        if (dest != root)
                btrfs_record_root_in_trans(trans, dest);
  
@@@ -7131,16 -7150,13 +7150,13 @@@ static int btrfs_symlink(struct inode *
        if (IS_ERR(trans))
                return PTR_ERR(trans);
  
-       btrfs_set_trans_block_group(trans, dir);
        err = btrfs_find_free_ino(root, &objectid);
        if (err)
                goto out_unlock;
  
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
                                dentry->d_name.len, btrfs_ino(dir), objectid,
-                               BTRFS_I(dir)->block_group, S_IFLNK|S_IRWXUGO,
-                               &index);
+                               S_IFLNK|S_IRWXUGO, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto out_unlock;
                goto out_unlock;
        }
  
-       btrfs_set_trans_block_group(trans, inode);
        err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
        if (err)
                drop_inode = 1;
                inode->i_op = &btrfs_file_inode_operations;
                BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
        }
-       btrfs_update_inode_block_group(trans, inode);
-       btrfs_update_inode_block_group(trans, dir);
        if (drop_inode)
                goto out_unlock;
  
diff --combined fs/btrfs/relocation.c
@@@ -677,6 -677,8 +677,8 @@@ struct backref_node *build_backref_tree
                err = -ENOMEM;
                goto out;
        }
+       path1->reada = 1;
+       path2->reada = 2;
  
        node = alloc_backref_node(cache);
        if (!node) {
@@@ -710,7 -712,7 +712,7 @@@ again
        WARN_ON(cur->checked);
        if (!list_empty(&cur->upper)) {
                /*
 -               * the backref was added previously when processsing
 +               * the backref was added previously when processing
                 * backref of type BTRFS_TREE_BLOCK_REF_KEY
                 */
                BUG_ON(!list_is_singular(&cur->upper));
@@@ -1999,6 -2001,7 +2001,7 @@@ static noinline_for_stack int merge_rel
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
+       path->reada = 1;
  
        reloc_root = root->reloc_root;
        root_item = &reloc_root->root_item;
@@@ -2139,10 -2142,10 +2142,10 @@@ int prepare_to_merge(struct reloc_contr
        u64 num_bytes = 0;
        int ret;
  
-       mutex_lock(&root->fs_info->trans_mutex);
+       spin_lock(&root->fs_info->trans_lock);
        rc->merging_rsv_size += root->nodesize * (BTRFS_MAX_LEVEL - 1) * 2;
        rc->merging_rsv_size += rc->nodes_relocated * 2;
-       mutex_unlock(&root->fs_info->trans_mutex);
+       spin_unlock(&root->fs_info->trans_lock);
  again:
        if (!err) {
                num_bytes = rc->merging_rsv_size;
                        err = ret;
        }
  
-       trans = btrfs_join_transaction(rc->extent_root, 1);
+       trans = btrfs_join_transaction(rc->extent_root);
        if (IS_ERR(trans)) {
                if (!err)
                        btrfs_block_rsv_release(rc->extent_root,
@@@ -2211,9 -2214,9 +2214,9 @@@ int merge_reloc_roots(struct reloc_cont
        int ret;
  again:
        root = rc->extent_root;
-       mutex_lock(&root->fs_info->trans_mutex);
+       spin_lock(&root->fs_info->trans_lock);
        list_splice_init(&rc->reloc_roots, &reloc_roots);
-       mutex_unlock(&root->fs_info->trans_mutex);
+       spin_unlock(&root->fs_info->trans_lock);
  
        while (!list_empty(&reloc_roots)) {
                found = 1;
@@@ -3236,7 -3239,7 +3239,7 @@@ truncate
                goto out;
        }
  
-       trans = btrfs_join_transaction(root, 0);
+       trans = btrfs_join_transaction(root);
        if (IS_ERR(trans)) {
                btrfs_free_path(path);
                ret = PTR_ERR(trans);
@@@ -3300,6 -3303,7 +3303,7 @@@ static int find_data_references(struct 
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
+       path->reada = 1;
  
        root = read_fs_root(rc->extent_root->fs_info, ref_root);
        if (IS_ERR(root)) {
@@@ -3586,17 -3590,17 +3590,17 @@@ next
  static void set_reloc_control(struct reloc_control *rc)
  {
        struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
-       mutex_lock(&fs_info->trans_mutex);
+       spin_lock(&fs_info->trans_lock);
        fs_info->reloc_ctl = rc;
-       mutex_unlock(&fs_info->trans_mutex);
+       spin_unlock(&fs_info->trans_lock);
  }
  
  static void unset_reloc_control(struct reloc_control *rc)
  {
        struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
-       mutex_lock(&fs_info->trans_mutex);
+       spin_lock(&fs_info->trans_lock);
        fs_info->reloc_ctl = NULL;
-       mutex_unlock(&fs_info->trans_mutex);
+       spin_unlock(&fs_info->trans_lock);
  }
  
  static int check_extent_flags(u64 flags)
@@@ -3645,7 -3649,7 +3649,7 @@@ int prepare_to_relocate(struct reloc_co
        rc->create_reloc_tree = 1;
        set_reloc_control(rc);
  
-       trans = btrfs_join_transaction(rc->extent_root, 1);
+       trans = btrfs_join_transaction(rc->extent_root);
        BUG_ON(IS_ERR(trans));
        btrfs_commit_transaction(trans, rc->extent_root);
        return 0;
@@@ -3668,6 -3672,7 +3672,7 @@@ static noinline_for_stack int relocate_
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
+       path->reada = 1;
  
        ret = prepare_to_relocate(rc);
        if (ret) {
@@@ -3834,7 -3839,7 +3839,7 @@@ restart
        btrfs_block_rsv_release(rc->extent_root, rc->block_rsv, (u64)-1);
  
        /* get rid of pinned extents */
-       trans = btrfs_join_transaction(rc->extent_root, 1);
+       trans = btrfs_join_transaction(rc->extent_root);
        if (IS_ERR(trans))
                err = PTR_ERR(trans);
        else
@@@ -4093,6 -4098,7 +4098,7 @@@ int btrfs_recover_relocation(struct btr
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
+       path->reada = -1;
  
        key.objectid = BTRFS_TREE_RELOC_OBJECTID;
        key.type = BTRFS_ROOT_ITEM_KEY;
  
        set_reloc_control(rc);
  
-       trans = btrfs_join_transaction(rc->extent_root, 1);
+       trans = btrfs_join_transaction(rc->extent_root);
        if (IS_ERR(trans)) {
                unset_reloc_control(rc);
                err = PTR_ERR(trans);
  
        unset_reloc_control(rc);
  
-       trans = btrfs_join_transaction(rc->extent_root, 1);
+       trans = btrfs_join_transaction(rc->extent_root);
        if (IS_ERR(trans))
                err = PTR_ERR(trans);
        else
diff --combined fs/btrfs/super.c
@@@ -39,7 -39,6 +39,7 @@@
  #include <linux/miscdevice.h>
  #include <linux/magic.h>
  #include <linux/slab.h>
 +#include <linux/cleancache.h>
  #include "compat.h"
  #include "delayed-inode.h"
  #include "ctree.h"
@@@ -161,7 -160,8 +161,8 @@@ enum 
        Opt_compress_type, Opt_compress_force, Opt_compress_force_type,
        Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard,
        Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed,
-       Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, Opt_err,
+       Opt_enospc_debug, Opt_subvolrootid, Opt_defrag,
+       Opt_inode_cache, Opt_err,
  };
  
  static match_table_t tokens = {
        {Opt_enospc_debug, "enospc_debug"},
        {Opt_subvolrootid, "subvolrootid=%d"},
        {Opt_defrag, "autodefrag"},
+       {Opt_inode_cache, "inode_cache"},
        {Opt_err, NULL},
  };
  
@@@ -361,6 -362,10 +363,10 @@@ int btrfs_parse_options(struct btrfs_ro
                        printk(KERN_INFO "btrfs: enabling disk space caching\n");
                        btrfs_set_opt(info->mount_opt, SPACE_CACHE);
                        break;
+               case Opt_inode_cache:
+                       printk(KERN_INFO "btrfs: enabling inode map caching\n");
+                       btrfs_set_opt(info->mount_opt, INODE_MAP_CACHE);
+                       break;
                case Opt_clear_cache:
                        printk(KERN_INFO "btrfs: force clearing of disk cache\n");
                        btrfs_set_opt(info->mount_opt, CLEAR_CACHE);
@@@ -633,7 -638,6 +639,7 @@@ static int btrfs_fill_super(struct supe
        sb->s_root = root_dentry;
  
        save_mount_options(sb, data);
 +      cleancache_init_fs(sb);
        return 0;
  
  fail_close: