Merge branch 'delayed_inode' into inode_numbers
authorChris Mason <chris.mason@oracle.com>
Sun, 22 May 2011 11:07:01 +0000 (07:07 -0400)
committerChris Mason <chris.mason@oracle.com>
Sun, 22 May 2011 11:07:01 +0000 (07:07 -0400)
Conflicts:
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/transaction.c

Signed-off-by: Chris Mason <chris.mason@oracle.com>
1  2 
fs/btrfs/btrfs_inode.h
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c

diff --combined fs/btrfs/btrfs_inode.h
index 8842a4195f916d8d7c4daf8770fc8adfbf739408,beefafd91f22d988951a1b0875e9ca95cd85222d..d0b0e43a6a8b1f75923511e6a6624fc9c401fe82
@@@ -22,6 -22,7 +22,7 @@@
  #include "extent_map.h"
  #include "extent_io.h"
  #include "ordered-data.h"
+ #include "delayed-inode.h"
  
  /* in memory btrfs inode */
  struct btrfs_inode {
         */
        unsigned force_compress:4;
  
+       struct btrfs_delayed_node *delayed_node;
        struct inode vfs_inode;
  };
  
+ extern unsigned char btrfs_filetype_table[];
  static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
  {
        return container_of(inode, struct btrfs_inode, vfs_inode);
  }
  
 +static inline u64 btrfs_ino(struct inode *inode)
 +{
 +      u64 ino = BTRFS_I(inode)->location.objectid;
 +
 +      if (ino <= BTRFS_FIRST_FREE_OBJECTID)
 +              ino = inode->i_ino;
 +      return ino;
 +}
 +
  static inline void btrfs_i_size_write(struct inode *inode, u64 size)
  {
        i_size_write(inode, size);
diff --combined fs/btrfs/ctree.h
index 11a103db286699a24162e4f6162bc3d65b45ff28,5d25129d011602e572401126a94b167743bfbe13..529c157000b1b77acb1f860ba00f1674666ab277
@@@ -105,12 -105,6 +105,12 @@@ struct btrfs_ordered_sum
  /* For storing free space cache */
  #define BTRFS_FREE_SPACE_OBJECTID -11ULL
  
 +/*
 + * The inode number assigned to the special inode for sotring
 + * free ino cache
 + */
 +#define BTRFS_FREE_INO_OBJECTID -12ULL
 +
  /* dummy objectid represents multiple objectids */
  #define BTRFS_MULTIPLE_OBJECTIDS -255ULL
  
@@@ -836,6 -830,9 +836,6 @@@ struct btrfs_block_group_cache 
        u64 bytes_super;
        u64 flags;
        u64 sectorsize;
 -      int extents_thresh;
 -      int free_extents;
 -      int total_bitmaps;
        unsigned int ro:1;
        unsigned int dirty:1;
        unsigned int iref:1;
        struct btrfs_space_info *space_info;
  
        /* free space cache stuff */
 -      spinlock_t tree_lock;
 -      struct rb_root free_space_offset;
 -      u64 free_space;
 +      struct btrfs_free_space_ctl *free_space_ctl;
  
        /* block group cache stuff */
        struct rb_node cache_node;
  struct reloc_control;
  struct btrfs_device;
  struct btrfs_fs_devices;
+ struct btrfs_delayed_root;
  struct btrfs_fs_info {
        u8 fsid[BTRFS_FSID_SIZE];
        u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
        /* logical->physical extent mapping */
        struct btrfs_mapping_tree mapping_tree;
  
-       /* block reservation for extent, checksum and root tree */
+       /*
+        * block reservation for extent, checksum, root tree and
+        * delayed dir index item
+        */
        struct btrfs_block_rsv global_block_rsv;
        /* block reservation for delay allocation */
        struct btrfs_block_rsv delalloc_block_rsv;
         * for the sys_munmap function call path
         */
        struct btrfs_workers fixup_workers;
+       struct btrfs_workers delayed_workers;
        struct task_struct *transaction_kthread;
        struct task_struct *cleaner_kthread;
        int thread_pool_size;
  
        /* filesystem state */
        u64 fs_state;
+       struct btrfs_delayed_root *delayed_root;
  };
  
  /*
@@@ -1108,16 -1114,6 +1115,16 @@@ struct btrfs_root 
        spinlock_t accounting_lock;
        struct btrfs_block_rsv *block_rsv;
  
 +      /* free ino cache stuff */
 +      struct mutex fs_commit_mutex;
 +      struct btrfs_free_space_ctl *free_ino_ctl;
 +      enum btrfs_caching_type cached;
 +      spinlock_t cache_lock;
 +      wait_queue_head_t cache_wait;
 +      struct btrfs_free_space_ctl *free_ino_pinned;
 +      u64 cache_progress;
 +      struct inode *cache_inode;
 +
        struct mutex log_mutex;
        wait_queue_head_t log_writer_wait;
        wait_queue_head_t log_commit_wait[2];
        /* red-black tree that keeps track of in-memory inodes */
        struct rb_root inode_tree;
  
+       /*
+        * radix tree that keeps track of delayed nodes of every inode,
+        * protected by inode_lock
+        */
+       struct radix_tree_root delayed_nodes_tree;
        /*
         * right now this just gets used so that a root has its own devid
         * for stat.  It may be used for more later
@@@ -2110,6 -2111,13 +2122,13 @@@ static inline bool btrfs_mixed_space_in
  }
  
  /* extent-tree.c */
+ static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root,
+                                                int num_items)
+ {
+       return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
+               3 * num_items;
+ }
  void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
  int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root, unsigned long count);
@@@ -2305,6 -2313,8 +2324,8 @@@ void btrfs_release_path(struct btrfs_ro
  struct btrfs_path *btrfs_alloc_path(void);
  void btrfs_free_path(struct btrfs_path *p);
  void btrfs_set_path_blocking(struct btrfs_path *p);
+ void btrfs_clear_path_blocking(struct btrfs_path *p,
+                              struct extent_buffer *held);
  void btrfs_unlock_up_safe(struct btrfs_path *p, int level);
  
  int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@@ -2316,6 -2326,10 +2337,10 @@@ static inline int btrfs_del_item(struc
        return btrfs_del_items(trans, root, path, path->slots[0], 1);
  }
  
+ int setup_items_for_insert(struct btrfs_trans_handle *trans,
+                          struct btrfs_root *root, struct btrfs_path *path,
+                          struct btrfs_key *cpu_key, u32 *data_size,
+                          u32 total_data, u32 total_size, int nr);
  int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, struct btrfs_key *key, void *data, u32 data_size);
  int btrfs_insert_some_items(struct btrfs_trans_handle *trans,
@@@ -2379,7 -2393,7 +2404,7 @@@ void btrfs_check_and_init_root_item(str
  /* dir-item.c */
  int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, const char *name,
-                         int name_len, u64 dir,
+                         int name_len, struct inode *dir,
                          struct btrfs_key *location, u8 type, u64 index);
  struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
                                             struct btrfs_root *root,
@@@ -2424,6 -2438,12 +2449,6 @@@ int btrfs_del_orphan_item(struct btrfs_
                          struct btrfs_root *root, u64 offset);
  int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset);
  
 -/* inode-map.c */
 -int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
 -                           struct btrfs_root *fs_root,
 -                           u64 dirid, u64 *objectid);
 -int btrfs_find_highest_inode(struct btrfs_root *fs_root, u64 *objectid);
 -
  /* inode-item.c */
  int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
diff --combined fs/btrfs/disk-io.c
index ac1cd20d1c0d758ccf4ef9c53a755e01b1430470,22c3c958604947a3257edb9b46b2e518a9efd733..087eed85c2505c5e70d5ad20b9e2ddb06e62937a
@@@ -41,7 -41,6 +41,7 @@@
  #include "locking.h"
  #include "tree-log.h"
  #include "free-space-cache.h"
 +#include "inode-map.h"
  
  static struct extent_io_ops btree_extent_io_ops;
  static void end_workqueue_fn(struct btrfs_work *work);
@@@ -1059,6 -1058,7 +1059,7 @@@ static int __setup_root(u32 nodesize, u
        root->name = NULL;
        root->in_sysfs = 0;
        root->inode_tree = RB_ROOT;
+       INIT_RADIX_TREE(&root->delayed_nodes_tree, GFP_ATOMIC);
        root->block_rsv = NULL;
        root->orphan_block_rsv = NULL;
  
@@@ -1327,19 -1327,6 +1328,19 @@@ again
        if (IS_ERR(root))
                return root;
  
 +      root->free_ino_ctl = kzalloc(sizeof(*root->free_ino_ctl), GFP_NOFS);
 +      if (!root->free_ino_ctl)
 +              goto fail;
 +      root->free_ino_pinned = kzalloc(sizeof(*root->free_ino_pinned),
 +                                      GFP_NOFS);
 +      if (!root->free_ino_pinned)
 +              goto fail;
 +
 +      btrfs_init_free_ino_ctl(root);
 +      mutex_init(&root->fs_commit_mutex);
 +      spin_lock_init(&root->cache_lock);
 +      init_waitqueue_head(&root->cache_wait);
 +
        set_anon_super(&root->anon_super, NULL);
  
        if (btrfs_root_refs(&root->root_item) == 0) {
@@@ -1707,6 -1694,13 +1708,13 @@@ struct btrfs_root *open_ctree(struct su
  
        INIT_LIST_HEAD(&fs_info->ordered_extents);
        spin_lock_init(&fs_info->ordered_extent_lock);
+       fs_info->delayed_root = kmalloc(sizeof(struct btrfs_delayed_root),
+                                       GFP_NOFS);
+       if (!fs_info->delayed_root) {
+               err = -ENOMEM;
+               goto fail_iput;
+       }
+       btrfs_init_delayed_root(fs_info->delayed_root);
  
        sb->s_blocksize = 4096;
        sb->s_blocksize_bits = blksize_bits(4096);
        bh = btrfs_read_dev_super(fs_devices->latest_bdev);
        if (!bh) {
                err = -EINVAL;
-               goto fail_iput;
+               goto fail_alloc;
        }
  
        memcpy(&fs_info->super_copy, bh->b_data, sizeof(fs_info->super_copy));
  
        disk_super = &fs_info->super_copy;
        if (!btrfs_super_root(disk_super))
-               goto fail_iput;
+               goto fail_alloc;
  
        /* check FS state, whether FS is broken. */
        fs_info->fs_state |= btrfs_super_flags(disk_super);
        ret = btrfs_parse_options(tree_root, options);
        if (ret) {
                err = ret;
-               goto fail_iput;
+               goto fail_alloc;
        }
  
        features = btrfs_super_incompat_flags(disk_super) &
                       "unsupported optional features (%Lx).\n",
                       (unsigned long long)features);
                err = -EINVAL;
-               goto fail_iput;
+               goto fail_alloc;
        }
  
        features = btrfs_super_incompat_flags(disk_super);
                       "unsupported option features (%Lx).\n",
                       (unsigned long long)features);
                err = -EINVAL;
-               goto fail_iput;
+               goto fail_alloc;
        }
  
        btrfs_init_workers(&fs_info->generic_worker,
                           &fs_info->generic_worker);
        btrfs_init_workers(&fs_info->endio_freespace_worker, "freespace-write",
                           1, &fs_info->generic_worker);
+       btrfs_init_workers(&fs_info->delayed_workers, "delayed-meta",
+                          fs_info->thread_pool_size,
+                          &fs_info->generic_worker);
  
        /*
         * endios are largely parallel and should have a very
        btrfs_start_workers(&fs_info->endio_meta_write_workers, 1);
        btrfs_start_workers(&fs_info->endio_write_workers, 1);
        btrfs_start_workers(&fs_info->endio_freespace_worker, 1);
+       btrfs_start_workers(&fs_info->delayed_workers, 1);
  
        fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
        fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
@@@ -2152,6 -2150,9 +2164,9 @@@ fail_sb_buffer
        btrfs_stop_workers(&fs_info->endio_write_workers);
        btrfs_stop_workers(&fs_info->endio_freespace_worker);
        btrfs_stop_workers(&fs_info->submit_workers);
+       btrfs_stop_workers(&fs_info->delayed_workers);
+ fail_alloc:
+       kfree(fs_info->delayed_root);
  fail_iput:
        invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
        iput(fs_info->btree_inode);
@@@ -2418,15 -2419,12 +2433,15 @@@ int btrfs_free_fs_root(struct btrfs_fs_
        if (btrfs_root_refs(&root->root_item) == 0)
                synchronize_srcu(&fs_info->subvol_srcu);
  
 +      __btrfs_remove_free_space_cache(root->free_ino_pinned);
 +      __btrfs_remove_free_space_cache(root->free_ino_ctl);
        free_fs_root(root);
        return 0;
  }
  
  static void free_fs_root(struct btrfs_root *root)
  {
 +      iput(root->cache_inode);
        WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree));
        if (root->anon_super.s_dev) {
                down_write(&root->anon_super.s_umount);
        }
        free_extent_buffer(root->node);
        free_extent_buffer(root->commit_root);
 +      kfree(root->free_ino_ctl);
 +      kfree(root->free_ino_pinned);
        kfree(root->name);
        kfree(root);
  }
@@@ -2597,6 -2593,7 +2612,7 @@@ int close_ctree(struct btrfs_root *root
        del_fs_roots(fs_info);
  
        iput(fs_info->btree_inode);
+       kfree(fs_info->delayed_root);
  
        btrfs_stop_workers(&fs_info->generic_worker);
        btrfs_stop_workers(&fs_info->fixup_workers);
        btrfs_stop_workers(&fs_info->endio_write_workers);
        btrfs_stop_workers(&fs_info->endio_freespace_worker);
        btrfs_stop_workers(&fs_info->submit_workers);
+       btrfs_stop_workers(&fs_info->delayed_workers);
  
        btrfs_close_devices(fs_info->fs_devices);
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
@@@ -2673,6 -2671,29 +2690,29 @@@ void btrfs_mark_buffer_dirty(struct ext
  }
  
  void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
+ {
+       /*
+        * looks as though older kernels can get into trouble with
+        * this code, they end up stuck in balance_dirty_pages forever
+        */
+       u64 num_dirty;
+       unsigned long thresh = 32 * 1024 * 1024;
+       if (current->flags & PF_MEMALLOC)
+               return;
+       btrfs_balance_delayed_items(root);
+       num_dirty = root->fs_info->dirty_metadata_bytes;
+       if (num_dirty > thresh) {
+               balance_dirty_pages_ratelimited_nr(
+                                  root->fs_info->btree_inode->i_mapping, 1);
+       }
+       return;
+ }
+ void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
  {
        /*
         * looks as though older kernels can get into trouble with
diff --combined fs/btrfs/extent-tree.c
index e530c20989fdc3fe8665c4ca09166cff8c609bbc,7b0433866f36daa01941dbe346094d7c59c14931..810d1f80b49713714ad21ae569e2ff3ace78c7db
@@@ -105,7 -105,6 +105,7 @@@ void btrfs_put_block_group(struct btrfs
                WARN_ON(cache->pinned > 0);
                WARN_ON(cache->reserved > 0);
                WARN_ON(cache->reserved_pinned > 0);
 +              kfree(cache->free_space_ctl);
                kfree(cache);
        }
  }
@@@ -3145,8 -3144,7 +3145,8 @@@ int btrfs_check_data_free_space(struct 
        /* make sure bytes are sectorsize aligned */
        bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1);
  
 -      if (root == root->fs_info->tree_root) {
 +      if (root == root->fs_info->tree_root ||
 +          BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID) {
                alloc_chunk = 0;
                committed = 1;
        }
@@@ -3975,12 -3973,6 +3975,6 @@@ static void release_global_block_rsv(st
        WARN_ON(fs_info->chunk_block_rsv.reserved > 0);
  }
  
- static u64 calc_trans_metadata_size(struct btrfs_root *root, int num_items)
- {
-       return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
-               3 * num_items;
- }
  int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root,
                                 int num_items)
        if (num_items == 0 || root->fs_info->chunk_root == root)
                return 0;
  
-       num_bytes = calc_trans_metadata_size(root, num_items);
+       num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
        ret = btrfs_block_rsv_add(trans, root, &root->fs_info->trans_block_rsv,
                                  num_bytes);
        if (!ret) {
@@@ -4030,14 -4022,14 +4024,14 @@@ int btrfs_orphan_reserve_metadata(struc
         * If all of the metadata space is used, we can commit
         * transaction and use space it freed.
         */
-       u64 num_bytes = calc_trans_metadata_size(root, 4);
+       u64 num_bytes = btrfs_calc_trans_metadata_size(root, 4);
        return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
  }
  
  void btrfs_orphan_release_metadata(struct inode *inode)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       u64 num_bytes = calc_trans_metadata_size(root, 4);
+       u64 num_bytes = btrfs_calc_trans_metadata_size(root, 4);
        btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes);
  }
  
@@@ -4051,7 -4043,7 +4045,7 @@@ int btrfs_snap_reserve_metadata(struct 
         * two for root back/forward refs, two for directory entries
         * and one for root of the snapshot.
         */
-       u64 num_bytes = calc_trans_metadata_size(root, 5);
+       u64 num_bytes = btrfs_calc_trans_metadata_size(root, 5);
        dst_rsv->space_info = src_rsv->space_info;
        return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
  }
@@@ -4080,7 -4072,7 +4074,7 @@@ int btrfs_delalloc_reserve_metadata(str
  
        if (nr_extents > reserved_extents) {
                nr_extents -= reserved_extents;
-               to_reserve = calc_trans_metadata_size(root, nr_extents);
+               to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
        } else {
                nr_extents = 0;
                to_reserve = 0;
@@@ -4134,7 -4126,7 +4128,7 @@@ void btrfs_delalloc_release_metadata(st
  
        to_free = calc_csum_metadata_size(inode, num_bytes);
        if (nr_extents > 0)
-               to_free += calc_trans_metadata_size(root, nr_extents);
+               to_free += btrfs_calc_trans_metadata_size(root, nr_extents);
  
        btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
                                to_free);
@@@ -4895,7 -4887,7 +4889,7 @@@ wait_block_group_cache_progress(struct 
                return 0;
  
        wait_event(caching_ctl->wait, block_group_cache_done(cache) ||
 -                 (cache->free_space >= num_bytes));
 +                 (cache->free_space_ctl->free_space >= num_bytes));
  
        put_caching_control(caching_ctl);
        return 0;
@@@ -7010,8 -7002,8 +7004,8 @@@ static noinline int get_new_locations(s
  
        cur_pos = extent_key->objectid - offset;
        last_byte = extent_key->objectid + extent_key->offset;
 -      ret = btrfs_lookup_file_extent(NULL, root, path, reloc_inode->i_ino,
 -                                     cur_pos, 0);
 +      ret = btrfs_lookup_file_extent(NULL, root, path,
 +                                     btrfs_ino(reloc_inode), cur_pos, 0);
        if (ret < 0)
                goto out;
        if (ret > 0) {
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
                if (found_key.offset != cur_pos ||
                    found_key.type != BTRFS_EXTENT_DATA_KEY ||
 -                  found_key.objectid != reloc_inode->i_ino)
 +                  found_key.objectid != btrfs_ino(reloc_inode))
                        break;
  
                fi = btrfs_item_ptr(leaf, path->slots[0],
@@@ -7180,7 -7172,7 +7174,7 @@@ next
                                break;
                }
  
 -              if (inode && key.objectid != inode->i_ino) {
 +              if (inode && key.objectid != btrfs_ino(inode)) {
                        BUG_ON(extent_locked);
                        btrfs_release_path(root, path);
                        mutex_unlock(&inode->i_mutex);
@@@ -7489,7 -7481,7 +7483,7 @@@ static noinline int invalidate_extent_c
                        continue;
                if (btrfs_file_extent_disk_bytenr(leaf, fi) == 0)
                        continue;
 -              if (!inode || inode->i_ino != key.objectid) {
 +              if (!inode || btrfs_ino(inode) != key.objectid) {
                        iput(inode);
                        inode = btrfs_ilookup(target_root->fs_info->sb,
                                              key.objectid, target_root, 1);
@@@ -8557,16 -8549,10 +8551,16 @@@ int btrfs_read_block_groups(struct btrf
                        ret = -ENOMEM;
                        goto error;
                }
 +              cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
 +                                              GFP_NOFS);
 +              if (!cache->free_space_ctl) {
 +                      kfree(cache);
 +                      ret = -ENOMEM;
 +                      goto error;
 +              }
  
                atomic_set(&cache->count, 1);
                spin_lock_init(&cache->lock);
 -              spin_lock_init(&cache->tree_lock);
                cache->fs_info = info;
                INIT_LIST_HEAD(&cache->list);
                INIT_LIST_HEAD(&cache->cluster_list);
                if (need_clear)
                        cache->disk_cache_state = BTRFS_DC_CLEAR;
  
 -              /*
 -               * we only want to have 32k of ram per block group for keeping
 -               * track of free space, and if we pass 1/2 of that we want to
 -               * start converting things over to using bitmaps
 -               */
 -              cache->extents_thresh = ((1024 * 32) / 2) /
 -                      sizeof(struct btrfs_free_space);
 -
                read_extent_buffer(leaf, &cache->item,
                                   btrfs_item_ptr_offset(leaf, path->slots[0]),
                                   sizeof(cache->item));
                cache->flags = btrfs_block_group_flags(&cache->item);
                cache->sectorsize = root->sectorsize;
  
 +              btrfs_init_free_space_ctl(cache);
 +
                /*
                 * We need to exclude the super stripes now so that the space
                 * info has super bytes accounted for, otherwise we'll think
@@@ -8672,12 -8664,6 +8666,12 @@@ int btrfs_make_block_group(struct btrfs
        cache = kzalloc(sizeof(*cache), GFP_NOFS);
        if (!cache)
                return -ENOMEM;
 +      cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
 +                                      GFP_NOFS);
 +      if (!cache->free_space_ctl) {
 +              kfree(cache);
 +              return -ENOMEM;
 +      }
  
        cache->key.objectid = chunk_offset;
        cache->key.offset = size;
        cache->sectorsize = root->sectorsize;
        cache->fs_info = root->fs_info;
  
 -      /*
 -       * we only want to have 32k of ram per block group for keeping track
 -       * of free space, and if we pass 1/2 of that we want to start
 -       * converting things over to using bitmaps
 -       */
 -      cache->extents_thresh = ((1024 * 32) / 2) /
 -              sizeof(struct btrfs_free_space);
        atomic_set(&cache->count, 1);
        spin_lock_init(&cache->lock);
 -      spin_lock_init(&cache->tree_lock);
        INIT_LIST_HEAD(&cache->list);
        INIT_LIST_HEAD(&cache->cluster_list);
  
 +      btrfs_init_free_space_ctl(cache);
 +
        btrfs_set_block_group_used(&cache->item, bytes_used);
        btrfs_set_block_group_chunk_objectid(&cache->item, chunk_objectid);
        cache->flags = type;
diff --combined fs/btrfs/inode.c
index 01438e9ba2e2c64a8de31dcd9c38403f89546a9e,3470f67c6258a42877f884625e4f099dcc9d9ed5..6cef48572e9e92c1ceedd3bcb9cf4d071e386a87
@@@ -51,7 -51,6 +51,7 @@@
  #include "compression.h"
  #include "locking.h"
  #include "free-space-cache.h"
 +#include "inode-map.h"
  
  struct btrfs_iget_args {
        u64 ino;
@@@ -139,7 -138,7 +139,7 @@@ static noinline int insert_inline_exten
        path->leave_spinning = 1;
        btrfs_set_trans_block_group(trans, inode);
  
 -      key.objectid = inode->i_ino;
 +      key.objectid = btrfs_ino(inode);
        key.offset = start;
        btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
        datasize = btrfs_file_extent_calc_inline_size(cur_size);
@@@ -746,15 -745,6 +746,15 @@@ static u64 get_extent_allocation_hint(s
        return alloc_hint;
  }
  
 +static inline bool is_free_space_inode(struct btrfs_root *root,
 +                                     struct inode *inode)
 +{
 +      if (root == root->fs_info->tree_root ||
 +          BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID)
 +              return true;
 +      return false;
 +}
 +
  /*
   * when extent_io.c finds a delayed allocation range in the file,
   * the call backs end up in this code.  The basic idea is to
@@@ -787,7 -777,7 +787,7 @@@ static noinline int cow_file_range(stru
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
        int ret = 0;
  
 -      BUG_ON(root == root->fs_info->tree_root);
 +      BUG_ON(is_free_space_inode(root, inode));
        trans = btrfs_join_transaction(root, 1);
        BUG_ON(IS_ERR(trans));
        btrfs_set_trans_block_group(trans, inode);
@@@ -1059,31 -1049,29 +1059,31 @@@ static noinline int run_delalloc_nocow(
        int type;
        int nocow;
        int check_prev = 1;
 -      bool nolock = false;
 +      bool nolock;
 +      u64 ino = btrfs_ino(inode);
  
        path = btrfs_alloc_path();
        BUG_ON(!path);
 -      if (root == root->fs_info->tree_root) {
 -              nolock = true;
 +
 +      nolock = is_free_space_inode(root, inode);
 +
 +      if (nolock)
                trans = btrfs_join_transaction_nolock(root, 1);
 -      } else {
 +      else
                trans = btrfs_join_transaction(root, 1);
 -      }
        BUG_ON(IS_ERR(trans));
  
        cow_start = (u64)-1;
        cur_offset = start;
        while (1) {
 -              ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
 +              ret = btrfs_lookup_file_extent(trans, root, path, ino,
                                               cur_offset, 0);
                BUG_ON(ret < 0);
                if (ret > 0 && path->slots[0] > 0 && check_prev) {
                        leaf = path->nodes[0];
                        btrfs_item_key_to_cpu(leaf, &found_key,
                                              path->slots[0] - 1);
 -                      if (found_key.objectid == inode->i_ino &&
 +                      if (found_key.objectid == ino &&
                            found_key.type == BTRFS_EXTENT_DATA_KEY)
                                path->slots[0]--;
                }
@@@ -1104,7 -1092,7 +1104,7 @@@ next_slot
                num_bytes = 0;
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
  
 -              if (found_key.objectid > inode->i_ino ||
 +              if (found_key.objectid > ino ||
                    found_key.type > BTRFS_EXTENT_DATA_KEY ||
                    found_key.offset > end)
                        break;
                                goto out_check;
                        if (btrfs_extent_readonly(root, disk_bytenr))
                                goto out_check;
 -                      if (btrfs_cross_ref_exist(trans, root, inode->i_ino,
 +                      if (btrfs_cross_ref_exist(trans, root, ino,
                                                  found_key.offset -
                                                  extent_offset, disk_bytenr))
                                goto out_check;
@@@ -1328,7 -1316,8 +1328,7 @@@ static int btrfs_set_bit_hook(struct in
        if (!(state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
                u64 len = state->end + 1 - state->start;
 -              int do_list = (root->root_key.objectid !=
 -                             BTRFS_ROOT_TREE_OBJECTID);
 +              bool do_list = !is_free_space_inode(root, inode);
  
                if (*bits & EXTENT_FIRST_DELALLOC)
                        *bits &= ~EXTENT_FIRST_DELALLOC;
@@@ -1361,7 -1350,8 +1361,7 @@@ static int btrfs_clear_bit_hook(struct 
        if ((state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
                u64 len = state->end + 1 - state->start;
 -              int do_list = (root->root_key.objectid !=
 -                             BTRFS_ROOT_TREE_OBJECTID);
 +              bool do_list = !is_free_space_inode(root, inode);
  
                if (*bits & EXTENT_FIRST_DELALLOC)
                        *bits &= ~EXTENT_FIRST_DELALLOC;
@@@ -1468,7 -1458,7 +1468,7 @@@ static int btrfs_submit_bio_hook(struc
  
        skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
  
 -      if (root == root->fs_info->tree_root)
 +      if (is_free_space_inode(root, inode))
                ret = btrfs_bio_wq_end_io(root->fs_info, bio, 2);
        else
                ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
@@@ -1654,7 -1644,7 +1654,7 @@@ static int insert_reserved_file_extent(
                                 &hint, 0);
        BUG_ON(ret);
  
 -      ins.objectid = inode->i_ino;
 +      ins.objectid = btrfs_ino(inode);
        ins.offset = file_pos;
        ins.type = BTRFS_EXTENT_DATA_KEY;
        ret = btrfs_insert_empty_item(trans, root, path, &ins, sizeof(*fi));
        ins.type = BTRFS_EXTENT_ITEM_KEY;
        ret = btrfs_alloc_reserved_file_extent(trans, root,
                                        root->root_key.objectid,
 -                                      inode->i_ino, file_pos, &ins);
 +                                      btrfs_ino(inode), file_pos, &ins);
        BUG_ON(ret);
        btrfs_free_path(path);
  
@@@ -1711,7 -1701,7 +1711,7 @@@ static int btrfs_finish_ordered_io(stru
        struct extent_state *cached_state = NULL;
        int compress_type = 0;
        int ret;
 -      bool nolock = false;
 +      bool nolock;
  
        ret = btrfs_dec_test_ordered_pending(inode, &ordered_extent, start,
                                             end - start + 1);
                return 0;
        BUG_ON(!ordered_extent);
  
 -      nolock = (root == root->fs_info->tree_root);
 +      nolock = is_free_space_inode(root, inode);
  
        if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
                BUG_ON(!list_empty(&ordered_extent->list));
@@@ -2015,9 -2005,8 +2015,9 @@@ good
  
  zeroit:
        if (printk_ratelimit()) {
 -              printk(KERN_INFO "btrfs csum failed ino %lu off %llu csum %u "
 -                     "private %llu\n", page->mapping->host->i_ino,
 +              printk(KERN_INFO "btrfs csum failed ino %llu off %llu csum %u "
 +                     "private %llu\n",
 +                     (unsigned long long)btrfs_ino(page->mapping->host),
                       (unsigned long long)start, csum,
                       (unsigned long long)private);
        }
@@@ -2255,7 -2244,7 +2255,7 @@@ int btrfs_orphan_add(struct btrfs_trans
  
        /* insert an orphan item to track this unlinked/truncated file */
        if (insert >= 1) {
 -              ret = btrfs_insert_orphan_item(trans, root, inode->i_ino);
 +              ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
                BUG_ON(ret);
        }
  
@@@ -2292,7 -2281,7 +2292,7 @@@ int btrfs_orphan_del(struct btrfs_trans
        spin_unlock(&root->orphan_lock);
  
        if (trans && delete_item) {
 -              ret = btrfs_del_orphan_item(trans, root, inode->i_ino);
 +              ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode));
                BUG_ON(ret);
        }
  
@@@ -2554,8 -2543,7 +2554,8 @@@ static void btrfs_read_locked_inode(str
         * try to precache a NULL acl entry for files that don't have
         * any xattrs or acls
         */
 -      maybe_acls = acls_after_inode_item(leaf, path->slots[0], inode->i_ino);
 +      maybe_acls = acls_after_inode_item(leaf, path->slots[0],
 +                                         btrfs_ino(inode));
        if (!maybe_acls)
                cache_no_acl(inode);
  
@@@ -2659,11 -2647,26 +2659,26 @@@ noinline int btrfs_update_inode(struct 
        struct extent_buffer *leaf;
        int ret;
  
 -      if (likely(root != root->fs_info->tree_root)) {
+       /*
+        * If root is tree root, it means this inode is used to
+        * store free space information. And these inodes are updated
+        * when committing the transaction, so they needn't delaye to
+        * be updated, or deadlock will occured.
+        */
++      if (!is_free_space_inode(root, inode)) {
+               ret = btrfs_delayed_update_inode(trans, root, inode);
+               if (!ret)
+                       btrfs_set_inode_last_trans(trans, inode);
+               return ret;
+       }
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
        path->leave_spinning = 1;
-       ret = btrfs_lookup_inode(trans, root, path,
-                                &BTRFS_I(inode)->location, 1);
+       ret = btrfs_lookup_inode(trans, root, path, &BTRFS_I(inode)->location,
+                                1);
        if (ret) {
                if (ret > 0)
                        ret = -ENOENT;
        btrfs_unlock_up_safe(path, 1);
        leaf = path->nodes[0];
        inode_item = btrfs_item_ptr(leaf, path->slots[0],
-                                 struct btrfs_inode_item);
+                                   struct btrfs_inode_item);
  
        fill_inode_item(trans, leaf, inode_item, inode);
        btrfs_mark_buffer_dirty(leaf);
@@@ -2684,7 -2687,6 +2699,6 @@@ failed
        return ret;
  }
  
  /*
   * unlink helper that gets used here in inode.c and in the tree logging
   * recovery code.  It remove a link in a directory with a given name, and
@@@ -2701,8 -2703,6 +2715,8 @@@ static int __btrfs_unlink_inode(struct 
        struct btrfs_dir_item *di;
        struct btrfs_key key;
        u64 index;
 +      u64 ino = btrfs_ino(inode);
 +      u64 dir_ino = btrfs_ino(dir);
  
        path = btrfs_alloc_path();
        if (!path) {
        }
  
        path->leave_spinning = 1;
 -      di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
 +      di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
                                    name, name_len, -1);
        if (IS_ERR(di)) {
                ret = PTR_ERR(di);
                goto err;
        btrfs_release_path(root, path);
  
 -      ret = btrfs_del_inode_ref(trans, root, name, name_len,
 -                                inode->i_ino,
 -                                dir->i_ino, &index);
 +      ret = btrfs_del_inode_ref(trans, root, name, name_len, ino,
 +                                dir_ino, &index);
        if (ret) {
                printk(KERN_INFO "btrfs failed to delete reference to %.*s, "
 -                     "inode %lu parent %lu\n", name_len, name,
 -                     inode->i_ino, dir->i_ino);
 +                     "inode %llu parent %llu\n", name_len, name,
 +                     (unsigned long long)ino, (unsigned long long)dir_ino);
                goto err;
        }
  
-       di = btrfs_lookup_dir_index_item(trans, root, path, dir_ino,
-                                        index, name, name_len, -1);
-       if (IS_ERR(di)) {
-               ret = PTR_ERR(di);
-               goto err;
-       }
-       if (!di) {
-               ret = -ENOENT;
+       ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
+       if (ret)
                goto err;
-       }
-       ret = btrfs_delete_one_dir_name(trans, root, path, di);
-       btrfs_release_path(root, path);
  
        ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
 -                                       inode, dir->i_ino);
 +                                       inode, dir_ino);
        BUG_ON(ret != 0 && ret != -ENOENT);
  
        ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
@@@ -2829,14 -2821,12 +2834,14 @@@ static struct btrfs_trans_handle *__unl
        int check_link = 1;
        int err = -ENOSPC;
        int ret;
 +      u64 ino = btrfs_ino(inode);
 +      u64 dir_ino = btrfs_ino(dir);
  
        trans = btrfs_start_transaction(root, 10);
        if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC)
                return trans;
  
 -      if (inode->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
 +      if (ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
                return ERR_PTR(-ENOSPC);
  
        /* check if there is someone else holds reference */
  
        if (ret == 0 && S_ISREG(inode->i_mode)) {
                ret = btrfs_lookup_file_extent(trans, root, path,
 -                                             inode->i_ino, (u64)-1, 0);
 +                                             ino, (u64)-1, 0);
                if (ret < 0) {
                        err = ret;
                        goto out;
                goto out;
        }
  
 -      di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
 +      di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
                                dentry->d_name.name, dentry->d_name.len, 0);
        if (IS_ERR(di)) {
                err = PTR_ERR(di);
  
        ref = btrfs_lookup_inode_ref(trans, root, path,
                                dentry->d_name.name, dentry->d_name.len,
 -                              inode->i_ino, dir->i_ino, 0);
 +                              ino, dir_ino, 0);
        if (IS_ERR(ref)) {
                err = PTR_ERR(ref);
                goto out;
        index = btrfs_inode_ref_index(path->nodes[0], ref);
        btrfs_release_path(root, path);
  
 -      di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino, index,
+       /*
+        * This is a commit root search, if we can lookup inode item and other
+        * relative items in the commit root, it means the transaction of
+        * dir/file creation has been committed, and the dir index item that we
+        * delay to insert has also been inserted into the commit root. So
+        * we needn't worry about the delayed insertion of the dir index item
+        * here.
+        */
 +      di = btrfs_lookup_dir_index_item(trans, root, path, dir_ino, index,
                                dentry->d_name.name, dentry->d_name.len, 0);
        if (IS_ERR(di)) {
                err = PTR_ERR(di);
@@@ -3014,13 -3012,12 +3027,13 @@@ int btrfs_unlink_subvol(struct btrfs_tr
        struct btrfs_key key;
        u64 index;
        int ret;
 +      u64 dir_ino = btrfs_ino(dir);
  
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
  
 -      di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
 +      di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
                                   name, name_len, -1);
        BUG_ON(!di || IS_ERR(di));
  
  
        ret = btrfs_del_root_ref(trans, root->fs_info->tree_root,
                                 objectid, root->root_key.objectid,
 -                               dir->i_ino, &index, name, name_len);
 +                               dir_ino, &index, name, name_len);
        if (ret < 0) {
                BUG_ON(ret != -ENOENT);
 -              di = btrfs_search_dir_index_item(root, path, dir->i_ino,
 +              di = btrfs_search_dir_index_item(root, path, dir_ino,
                                                 name, name_len);
                BUG_ON(!di || IS_ERR(di));
  
                btrfs_release_path(root, path);
                index = key.offset;
        }
+       btrfs_release_path(root, path);
  
-       di = btrfs_lookup_dir_index_item(trans, root, path, dir_ino,
-                                        index, name, name_len, -1);
-       BUG_ON(!di || IS_ERR(di));
-       leaf = path->nodes[0];
-       btrfs_dir_item_key_to_cpu(leaf, di, &key);
-       WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
-       ret = btrfs_delete_one_dir_name(trans, root, path, di);
+       ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
        BUG_ON(ret);
-       btrfs_release_path(root, path);
  
        btrfs_i_size_write(dir, dir->i_size - name_len * 2);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
        ret = btrfs_update_inode(trans, root, dir);
        BUG_ON(ret);
  
-       btrfs_free_path(path);
        return 0;
  }
  
@@@ -3075,7 -3064,7 +3080,7 @@@ static int btrfs_rmdir(struct inode *di
        unsigned long nr = 0;
  
        if (inode->i_size > BTRFS_EMPTY_DIR_SIZE ||
 -          inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
 +          btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID)
                return -ENOTEMPTY;
  
        trans = __unlink_start_trans(dir, dentry);
  
        btrfs_set_trans_block_group(trans, dir);
  
 -      if (unlikely(inode->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
 +      if (unlikely(btrfs_ino(inode) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
                err = btrfs_unlink_subvol(trans, root, dir,
                                          BTRFS_I(inode)->location.objectid,
                                          dentry->d_name.name,
@@@ -3316,18 -3305,26 +3321,27 @@@ int btrfs_truncate_inode_items(struct b
        int encoding;
        int ret;
        int err = 0;
 +      u64 ino = btrfs_ino(inode);
  
        BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY);
  
        if (root->ref_cows || root == root->fs_info->tree_root)
                btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0);
  
+       /*
+        * This function is also used to drop the items in the log tree before
+        * we relog the inode, so if root != BTRFS_I(inode)->root, it means
+        * it is used to drop the loged items. So we shouldn't kill the delayed
+        * items.
+        */
+       if (min_type == 0 && root == BTRFS_I(inode)->root)
+               btrfs_kill_delayed_inode_items(inode);
        path = btrfs_alloc_path();
        BUG_ON(!path);
        path->reada = -1;
  
 -      key.objectid = inode->i_ino;
 +      key.objectid = ino;
        key.offset = (u64)-1;
        key.type = (u8)-1;
  
@@@ -3355,7 -3352,7 +3369,7 @@@ search_again
                found_type = btrfs_key_type(&found_key);
                encoding = 0;
  
 -              if (found_key.objectid != inode->i_ino)
 +              if (found_key.objectid != ino)
                        break;
  
                if (found_type < min_type)
@@@ -3474,7 -3471,7 +3488,7 @@@ delete
                        ret = btrfs_free_extent(trans, root, extent_start,
                                                extent_num_bytes, 0,
                                                btrfs_header_owner(leaf),
 -                                              inode->i_ino, extent_offset);
 +                                              ino, extent_offset);
                        BUG_ON(ret);
                }
  
  
                if (path->slots[0] == 0 ||
                    path->slots[0] != pending_del_slot) {
 -                      if (root->ref_cows) {
 +                      if (root->ref_cows &&
 +                          BTRFS_I(inode)->location.objectid !=
 +                                              BTRFS_FREE_INO_OBJECTID) {
                                err = -EAGAIN;
                                goto out;
                        }
@@@ -3675,7 -3670,7 +3689,7 @@@ int btrfs_cont_expand(struct inode *ino
                                break;
  
                        err = btrfs_insert_file_extent(trans, root,
 -                                      inode->i_ino, cur_offset, 0,
 +                                      btrfs_ino(inode), cur_offset, 0,
                                        0, hole_size, 0, hole_size,
                                        0, 0, 0);
                        if (err)
@@@ -3777,7 -3772,7 +3791,7 @@@ void btrfs_evict_inode(struct inode *in
  
        truncate_inode_pages(&inode->i_data, 0);
        if (inode->i_nlink && (btrfs_root_refs(&root->root_item) != 0 ||
 -                             root == root->fs_info->tree_root))
 +                             is_free_space_inode(root, inode)))
                goto no_delete;
  
        if (is_bad_inode(inode)) {
                BUG_ON(ret);
        }
  
 +      if (!(root == root->fs_info->tree_root ||
 +            root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID))
 +              btrfs_return_ino(root, btrfs_ino(inode));
 +
        nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty(root, nr);
@@@ -3859,7 -3850,7 +3873,7 @@@ static int btrfs_inode_by_name(struct i
        path = btrfs_alloc_path();
        BUG_ON(!path);
  
 -      di = btrfs_lookup_dir_item(NULL, root, path, dir->i_ino, name,
 +      di = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(dir), name,
                                    namelen, 0);
        if (IS_ERR(di))
                ret = PTR_ERR(di);
@@@ -3912,7 -3903,7 +3926,7 @@@ static int fixup_tree_root_location(str
  
        leaf = path->nodes[0];
        ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
 -      if (btrfs_root_ref_dirid(leaf, ref) != dir->i_ino ||
 +      if (btrfs_root_ref_dirid(leaf, ref) != btrfs_ino(dir) ||
            btrfs_root_ref_name_len(leaf, ref) != dentry->d_name.len)
                goto out;
  
@@@ -3951,7 -3942,6 +3965,7 @@@ static void inode_tree_add(struct inod
        struct btrfs_inode *entry;
        struct rb_node **p;
        struct rb_node *parent;
 +      u64 ino = btrfs_ino(inode);
  again:
        p = &root->inode_tree.rb_node;
        parent = NULL;
                parent = *p;
                entry = rb_entry(parent, struct btrfs_inode, rb_node);
  
 -              if (inode->i_ino < entry->vfs_inode.i_ino)
 +              if (ino < btrfs_ino(&entry->vfs_inode))
                        p = &parent->rb_left;
 -              else if (inode->i_ino > entry->vfs_inode.i_ino)
 +              else if (ino > btrfs_ino(&entry->vfs_inode))
                        p = &parent->rb_right;
                else {
                        WARN_ON(!(entry->vfs_inode.i_state &
@@@ -4030,9 -4020,9 +4044,9 @@@ again
                prev = node;
                entry = rb_entry(node, struct btrfs_inode, rb_node);
  
 -              if (objectid < entry->vfs_inode.i_ino)
 +              if (objectid < btrfs_ino(&entry->vfs_inode))
                        node = node->rb_left;
 -              else if (objectid > entry->vfs_inode.i_ino)
 +              else if (objectid > btrfs_ino(&entry->vfs_inode))
                        node = node->rb_right;
                else
                        break;
        if (!node) {
                while (prev) {
                        entry = rb_entry(prev, struct btrfs_inode, rb_node);
 -                      if (objectid <= entry->vfs_inode.i_ino) {
 +                      if (objectid <= btrfs_ino(&entry->vfs_inode)) {
                                node = prev;
                                break;
                        }
        }
        while (node) {
                entry = rb_entry(node, struct btrfs_inode, rb_node);
 -              objectid = entry->vfs_inode.i_ino + 1;
 +              objectid = btrfs_ino(&entry->vfs_inode) + 1;
                inode = igrab(&entry->vfs_inode);
                if (inode) {
                        spin_unlock(&root->inode_lock);
@@@ -4087,7 -4077,7 +4101,7 @@@ static int btrfs_init_locked_inode(stru
  static int btrfs_find_actor(struct inode *inode, void *opaque)
  {
        struct btrfs_iget_args *args = opaque;
 -      return args->ino == inode->i_ino &&
 +      return args->ino == btrfs_ino(inode) &&
                args->root == BTRFS_I(inode)->root;
  }
  
@@@ -4232,7 -4222,7 +4246,7 @@@ static struct dentry *btrfs_lookup(stru
        return d_splice_alias(inode, dentry);
  }
  
static unsigned char btrfs_filetype_table[] = {
+ unsigned char btrfs_filetype_table[] = {
        DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
  };
  
@@@ -4246,6 -4236,8 +4260,8 @@@ static int btrfs_real_readdir(struct fi
        struct btrfs_key key;
        struct btrfs_key found_key;
        struct btrfs_path *path;
+       struct list_head ins_list;
+       struct list_head del_list;
        int ret;
        struct extent_buffer *leaf;
        int slot;
        char tmp_name[32];
        char *name_ptr;
        int name_len;
+       int is_curr = 0;        /* filp->f_pos points to the current index? */
  
        /* FIXME, use a real flag for deciding about the key type */
        if (root->fs_info->tree_root == root)
  
        /* special case for "." */
        if (filp->f_pos == 0) {
 -              over = filldir(dirent, ".", 1,
 -                             1, inode->i_ino,
 -                             DT_DIR);
 +              over = filldir(dirent, ".", 1, 1, btrfs_ino(inode), DT_DIR);
                if (over)
                        return 0;
                filp->f_pos = 1;
                filp->f_pos = 2;
        }
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
        path->reada = 2;
  
+       if (key_type == BTRFS_DIR_INDEX_KEY) {
+               INIT_LIST_HEAD(&ins_list);
+               INIT_LIST_HEAD(&del_list);
+               btrfs_get_delayed_items(inode, &ins_list, &del_list);
+       }
        btrfs_set_key_type(&key, key_type);
        key.offset = filp->f_pos;
 -      key.objectid = inode->i_ino;
 +      key.objectid = btrfs_ino(inode);
  
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
        if (ret < 0)
                        break;
                if (found_key.offset < filp->f_pos)
                        goto next;
+               if (key_type == BTRFS_DIR_INDEX_KEY &&
+                   btrfs_should_delete_dir_index(&del_list,
+                                                 found_key.offset))
+                       goto next;
  
                filp->f_pos = found_key.offset;
+               is_curr = 1;
  
                di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
                di_cur = 0;
@@@ -4367,6 -4375,15 +4397,15 @@@ next
                path->slots[0]++;
        }
  
+       if (key_type == BTRFS_DIR_INDEX_KEY) {
+               if (is_curr)
+                       filp->f_pos++;
+               ret = btrfs_readdir_delayed_dir_index(filp, dirent, filldir,
+                                                     &ins_list);
+               if (ret)
+                       goto nopos;
+       }
        /* Reached end of directory/root. Bump pos past the last item. */
        if (key_type == BTRFS_DIR_INDEX_KEY)
                /*
  nopos:
        ret = 0;
  err:
+       if (key_type == BTRFS_DIR_INDEX_KEY)
+               btrfs_put_delayed_items(&ins_list, &del_list);
        btrfs_free_path(path);
        return ret;
  }
@@@ -4394,8 -4413,7 +4435,8 @@@ int btrfs_write_inode(struct inode *ino
                return 0;
  
        smp_mb();
 -      nolock = (root->fs_info->closing && root == root->fs_info->tree_root);
 +      if (root->fs_info->closing && is_free_space_inode(root, inode))
 +              nolock = true;
  
        if (wbc->sync_mode == WB_SYNC_ALL) {
                if (nolock)
@@@ -4440,9 -4458,8 +4481,9 @@@ void btrfs_dirty_inode(struct inode *in
                if (IS_ERR(trans)) {
                        if (printk_ratelimit()) {
                                printk(KERN_ERR "btrfs: fail to "
 -                                     "dirty  inode %lu error %ld\n",
 -                                     inode->i_ino, PTR_ERR(trans));
 +                                     "dirty  inode %llu error %ld\n",
 +                                     (unsigned long long)btrfs_ino(inode),
 +                                     PTR_ERR(trans));
                        }
                        return;
                }
                if (ret) {
                        if (printk_ratelimit()) {
                                printk(KERN_ERR "btrfs: fail to "
 -                                     "dirty  inode %lu error %d\n",
 -                                     inode->i_ino, ret);
 +                                     "dirty  inode %llu error %d\n",
 +                                     (unsigned long long)btrfs_ino(inode),
 +                                     ret);
                        }
                }
        }
        btrfs_end_transaction(trans, root);
+       if (BTRFS_I(inode)->delayed_node)
+               btrfs_balance_delayed_items(root);
  }
  
  /*
@@@ -4474,7 -4492,7 +4517,7 @@@ static int btrfs_set_inode_index_count(
        struct extent_buffer *leaf;
        int ret;
  
 -      key.objectid = inode->i_ino;
 +      key.objectid = btrfs_ino(inode);
        btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
        key.offset = (u64)-1;
  
        leaf = path->nodes[0];
        btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
  
 -      if (found_key.objectid != inode->i_ino ||
 +      if (found_key.objectid != btrfs_ino(inode) ||
            btrfs_key_type(&found_key) != BTRFS_DIR_INDEX_KEY) {
                BTRFS_I(inode)->index_cnt = 2;
                goto out;
@@@ -4527,9 -4545,12 +4570,12 @@@ int btrfs_set_inode_index(struct inode 
        int ret = 0;
  
        if (BTRFS_I(dir)->index_cnt == (u64)-1) {
-               ret = btrfs_set_inode_index_count(dir);
-               if (ret)
-                       return ret;
+               ret = btrfs_inode_delayed_dir_index_count(dir);
+               if (ret) {
+                       ret = btrfs_set_inode_index_count(dir);
+                       if (ret)
+                               return ret;
+               }
        }
  
        *index = BTRFS_I(dir)->index_cnt;
@@@ -4565,12 -4586,6 +4611,12 @@@ static struct inode *btrfs_new_inode(st
                return ERR_PTR(-ENOMEM);
        }
  
 +      /*
 +       * we have to initialize this early, so we can reclaim the inode
 +       * number if we fail afterwards in this function.
 +       */
 +      inode->i_ino = objectid;
 +
        if (dir) {
                trace_btrfs_inode_request(dir);
  
                goto fail;
  
        inode_init_owner(inode, dir, mode);
 -      inode->i_ino = objectid;
        inode_set_bytes(inode, 0);
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
@@@ -4679,29 -4695,29 +4725,29 @@@ int btrfs_add_link(struct btrfs_trans_h
        int ret = 0;
        struct btrfs_key key;
        struct btrfs_root *root = BTRFS_I(parent_inode)->root;
 +      u64 ino = btrfs_ino(inode);
 +      u64 parent_ino = btrfs_ino(parent_inode);
  
 -      if (unlikely(inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)) {
 +      if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) {
                memcpy(&key, &BTRFS_I(inode)->root->root_key, sizeof(key));
        } else {
 -              key.objectid = inode->i_ino;
 +              key.objectid = ino;
                btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
                key.offset = 0;
        }
  
 -      if (unlikely(inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)) {
 +      if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) {
                ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
                                         key.objectid, root->root_key.objectid,
 -                                       parent_inode->i_ino,
 -                                       index, name, name_len);
 +                                       parent_ino, index, name, name_len);
        } else if (add_backref) {
 -              ret = btrfs_insert_inode_ref(trans, root,
 -                                           name, name_len, inode->i_ino,
 -                                           parent_inode->i_ino, index);
 +              ret = btrfs_insert_inode_ref(trans, root, name, name_len, ino,
 +                                           parent_ino, index);
        }
  
        if (ret == 0) {
                ret = btrfs_insert_dir_item(trans, root, name, name_len,
-                                           parent_ino, &key,
+                                           parent_inode, &key,
                                            btrfs_inode_type(inode), index);
                BUG_ON(ret);
  
@@@ -4744,6 -4760,10 +4790,6 @@@ static int btrfs_mknod(struct inode *di
        if (!new_valid_dev(rdev))
                return -EINVAL;
  
 -      err = btrfs_find_free_objectid(NULL, root, dir->i_ino, &objectid);
 -      if (err)
 -              return err;
 -
        /*
         * 2 for inode item and ref
         * 2 for dir items
  
        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, dir->i_ino, objectid,
 +                              dentry->d_name.len, btrfs_ino(dir), objectid,
                                BTRFS_I(dir)->block_group, mode, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
@@@ -4807,6 -4823,9 +4853,6 @@@ static int btrfs_create(struct inode *d
        u64 objectid;
        u64 index = 0;
  
 -      err = btrfs_find_free_objectid(NULL, root, dir->i_ino, &objectid);
 -      if (err)
 -              return err;
        /*
         * 2 for inode item and ref
         * 2 for dir items
  
        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, dir->i_ino, objectid,
 +                              dentry->d_name.len, btrfs_ino(dir), objectid,
                                BTRFS_I(dir)->block_group, mode, &index);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
@@@ -4934,6 -4949,10 +4980,6 @@@ static int btrfs_mkdir(struct inode *di
        u64 index = 0;
        unsigned long nr = 1;
  
 -      err = btrfs_find_free_objectid(NULL, root, dir->i_ino, &objectid);
 -      if (err)
 -              return err;
 -
        /*
         * 2 items for inode and ref
         * 2 items for dir items
                return PTR_ERR(trans);
        btrfs_set_trans_block_group(trans, dir);
  
 +      err = btrfs_find_free_ino(root, &objectid);
 +      if (err)
 +              goto out_fail;
 +
        inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
 -                              dentry->d_name.len, dir->i_ino, objectid,
 +                              dentry->d_name.len, btrfs_ino(dir), objectid,
                                BTRFS_I(dir)->block_group, S_IFDIR | mode,
                                &index);
        if (IS_ERR(inode)) {
@@@ -5072,7 -5087,7 +5118,7 @@@ struct extent_map *btrfs_get_extent(str
        u64 bytenr;
        u64 extent_start = 0;
        u64 extent_end = 0;
 -      u64 objectid = inode->i_ino;
 +      u64 objectid = btrfs_ino(inode);
        u32 found_type;
        struct btrfs_path *path = NULL;
        struct btrfs_root *root = BTRFS_I(inode)->root;
@@@ -5580,7 -5595,7 +5626,7 @@@ static noinline int can_nocow_odirect(s
        if (!path)
                return -ENOMEM;
  
 -      ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
 +      ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode),
                                       offset, 0);
        if (ret < 0)
                goto out;
        ret = 0;
        leaf = path->nodes[0];
        btrfs_item_key_to_cpu(leaf, &key, slot);
 -      if (key.objectid != inode->i_ino ||
 +      if (key.objectid != btrfs_ino(inode) ||
            key.type != BTRFS_EXTENT_DATA_KEY) {
                /* not our file or wrong item type, must cow */
                goto out;
         * look for other files referencing this extent, if we
         * find any we must cow
         */
 -      if (btrfs_cross_ref_exist(trans, root, inode->i_ino,
 +      if (btrfs_cross_ref_exist(trans, root, btrfs_ino(inode),
                                  key.offset - backref_offset, disk_bytenr))
                goto out;
  
@@@ -5821,10 -5836,9 +5867,10 @@@ static void btrfs_endio_direct_read(str
  
                        flush_dcache_page(bvec->bv_page);
                        if (csum != *private) {
 -                              printk(KERN_ERR "btrfs csum failed ino %lu off"
 +                              printk(KERN_ERR "btrfs csum failed ino %llu off"
                                      " %llu csum %u private %u\n",
 -                                    inode->i_ino, (unsigned long long)start,
 +                                    (unsigned long long)btrfs_ino(inode),
 +                                    (unsigned long long)start,
                                      csum, *private);
                                err = -EIO;
                        }
@@@ -5971,9 -5985,9 +6017,9 @@@ static void btrfs_end_dio_bio(struct bi
        struct btrfs_dio_private *dip = bio->bi_private;
  
        if (err) {
 -              printk(KERN_ERR "btrfs direct IO failed ino %lu rw %lu "
 +              printk(KERN_ERR "btrfs direct IO failed ino %llu rw %lu "
                      "sector %#Lx len %u err no %d\n",
 -                    dip->inode->i_ino, bio->bi_rw,
 +                    (unsigned long long)btrfs_ino(dip->inode), bio->bi_rw,
                      (unsigned long long)bio->bi_sector, bio->bi_size, err);
                dip->errors = 1;
  
@@@ -6816,6 -6830,8 +6862,8 @@@ struct inode *btrfs_alloc_inode(struct 
        ei->dummy_inode = 0;
        ei->force_compress = BTRFS_COMPRESS_NONE;
  
+       ei->delayed_node = NULL;
        inode = &ei->vfs_inode;
        extent_map_tree_init(&ei->extent_tree, GFP_NOFS);
        extent_io_tree_init(&ei->io_tree, &inode->i_data, GFP_NOFS);
@@@ -6883,8 -6899,8 +6931,8 @@@ void btrfs_destroy_inode(struct inode *
  
        spin_lock(&root->orphan_lock);
        if (!list_empty(&BTRFS_I(inode)->i_orphan)) {
 -              printk(KERN_INFO "BTRFS: inode %lu still on the orphan list\n",
 -                     inode->i_ino);
 +              printk(KERN_INFO "BTRFS: inode %llu still on the orphan list\n",
 +                     (unsigned long long)btrfs_ino(inode));
                list_del_init(&BTRFS_I(inode)->i_orphan);
        }
        spin_unlock(&root->orphan_lock);
        inode_tree_del(inode);
        btrfs_drop_extent_cache(inode, 0, (u64)-1, 0);
  free:
+       btrfs_remove_delayed_node(inode);
        call_rcu(&inode->i_rcu, btrfs_i_callback);
  }
  
@@@ -6914,7 -6931,7 +6963,7 @@@ int btrfs_drop_inode(struct inode *inod
        struct btrfs_root *root = BTRFS_I(inode)->root;
  
        if (btrfs_root_refs(&root->root_item) == 0 &&
 -          root != root->fs_info->tree_root)
 +          !is_free_space_inode(root, inode))
                return 1;
        else
                return generic_drop_inode(inode);
@@@ -7023,17 -7040,16 +7072,17 @@@ static int btrfs_rename(struct inode *o
        u64 index = 0;
        u64 root_objectid;
        int ret;
 +      u64 old_ino = btrfs_ino(old_inode);
  
 -      if (new_dir->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
 +      if (btrfs_ino(new_dir) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
                return -EPERM;
  
        /* we only allow rename subvolume link between subvolumes */
 -      if (old_inode->i_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest)
 +      if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest)
                return -EXDEV;
  
 -      if (old_inode->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID ||
 -          (new_inode && new_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID))
 +      if (old_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID ||
 +          (new_inode && btrfs_ino(new_inode) == BTRFS_FIRST_FREE_OBJECTID))
                return -ENOTEMPTY;
  
        if (S_ISDIR(old_inode->i_mode) && new_inode &&
                filemap_flush(old_inode->i_mapping);
  
        /* close the racy window with snapshot create/destroy ioctl */
 -      if (old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
 +      if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
                down_read(&root->fs_info->subvol_sem);
        /*
         * We want to reserve the absolute worst case amount of items.  So if
        if (ret)
                goto out_fail;
  
 -      if (unlikely(old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)) {
 +      if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) {
                /* force full log commit if subvolume involved. */
                root->fs_info->last_trans_log_full_commit = trans->transid;
        } else {
                ret = btrfs_insert_inode_ref(trans, dest,
                                             new_dentry->d_name.name,
                                             new_dentry->d_name.len,
 -                                           old_inode->i_ino,
 -                                           new_dir->i_ino, index);
 +                                           old_ino,
 +                                           btrfs_ino(new_dir), index);
                if (ret)
                        goto out_fail;
                /*
         * make sure the inode gets flushed if it is replacing
         * something.
         */
 -      if (new_inode && new_inode->i_size &&
 -          old_inode && S_ISREG(old_inode->i_mode)) {
 +      if (new_inode && new_inode->i_size && S_ISREG(old_inode->i_mode))
                btrfs_add_ordered_operation(trans, root, old_inode);
 -      }
  
        old_dir->i_ctime = old_dir->i_mtime = ctime;
        new_dir->i_ctime = new_dir->i_mtime = ctime;
        if (old_dentry->d_parent != new_dentry->d_parent)
                btrfs_record_unlink_dir(trans, old_dir, old_inode, 1);
  
 -      if (unlikely(old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)) {
 +      if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) {
                root_objectid = BTRFS_I(old_inode)->root->root_key.objectid;
                ret = btrfs_unlink_subvol(trans, root, old_dir, root_objectid,
                                        old_dentry->d_name.name,
  
        if (new_inode) {
                new_inode->i_ctime = CURRENT_TIME;
 -              if (unlikely(new_inode->i_ino ==
 +              if (unlikely(btrfs_ino(new_inode) ==
                             BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
                        root_objectid = BTRFS_I(new_inode)->location.objectid;
                        ret = btrfs_unlink_subvol(trans, dest, new_dir,
                             new_dentry->d_name.len, 0, index);
        BUG_ON(ret);
  
 -      if (old_inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) {
 +      if (old_ino != BTRFS_FIRST_FREE_OBJECTID) {
                struct dentry *parent = dget_parent(new_dentry);
                btrfs_log_new_name(trans, old_inode, old_dir, parent);
                dput(parent);
  out_fail:
        btrfs_end_transaction_throttle(trans, root);
  out_notrans:
 -      if (old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
 +      if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
                up_read(&root->fs_info->subvol_sem);
  
        return ret;
@@@ -7291,6 -7309,9 +7340,6 @@@ static int btrfs_symlink(struct inode *
        if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root))
                return -ENAMETOOLONG;
  
 -      err = btrfs_find_free_objectid(NULL, root, dir->i_ino, &objectid);
 -      if (err)
 -              return err;
        /*
         * 2 items for inode item and ref
         * 2 items for dir items
  
        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, dir->i_ino, objectid,
 +                              dentry->d_name.len, btrfs_ino(dir), objectid,
                                BTRFS_I(dir)->block_group, S_IFLNK|S_IRWXUGO,
                                &index);
        if (IS_ERR(inode)) {
  
        path = btrfs_alloc_path();
        BUG_ON(!path);
 -      key.objectid = inode->i_ino;
 +      key.objectid = btrfs_ino(inode);
        key.offset = 0;
        btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
        datasize = btrfs_file_extent_calc_inline_size(name_len);
diff --combined fs/btrfs/ioctl.c
index bc5c2b01bf337b2aedc591076148958609b8398b,df59401af742d3279a807f13f3eef545c4be5a39..7ab39db3db0f7c953c1aabbef027eab0387c7808
@@@ -50,7 -50,6 +50,7 @@@
  #include "print-tree.h"
  #include "volumes.h"
  #include "locking.h"
 +#include "inode-map.h"
  
  /* Mask out flags that are inappropriate for the given type of inode. */
  static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
@@@ -330,7 -329,8 +330,7 @@@ static noinline int create_subvol(struc
        u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
        u64 index = 0;
  
 -      ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root,
 -                                     0, &objectid);
 +      ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid);
        if (ret) {
                dput(parent);
                return ret;
        BUG_ON(ret);
  
        ret = btrfs_insert_dir_item(trans, root,
-                                   name, namelen, btrfs_ino(dir), &key,
+                                   name, namelen, dir, &key,
                                    BTRFS_FT_DIR, index);
        if (ret)
                goto fail;
  
        ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
                                 objectid, root->root_key.objectid,
 -                               dir->i_ino, index, name, namelen);
 +                               btrfs_ino(dir), index, name, namelen);
  
        BUG_ON(ret);
  
@@@ -1129,7 -1129,7 +1129,7 @@@ static noinline int btrfs_ioctl_subvol_
        int ret = 0;
        u64 flags = 0;
  
 -      if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID)
 +      if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID)
                return -EINVAL;
  
        down_read(&root->fs_info->subvol_sem);
@@@ -1156,7 -1156,7 +1156,7 @@@ static noinline int btrfs_ioctl_subvol_
        if (root->fs_info->sb->s_flags & MS_RDONLY)
                return -EROFS;
  
 -      if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID)
 +      if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID)
                return -EINVAL;
  
        if (copy_from_user(&flags, arg, sizeof(flags)))
@@@ -1639,7 -1639,7 +1639,7 @@@ static noinline int btrfs_ioctl_snap_de
                        goto out_dput;
        }
  
 -      if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) {
 +      if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) {
                err = -EINVAL;
                goto out_dput;
        }
@@@ -1925,7 -1925,7 +1925,7 @@@ static noinline long btrfs_ioctl_clone(
        }
  
        /* clone data */
 -      key.objectid = src->i_ino;
 +      key.objectid = btrfs_ino(src);
        key.type = BTRFS_EXTENT_DATA_KEY;
        key.offset = 0;
  
  
                btrfs_item_key_to_cpu(leaf, &key, slot);
                if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY ||
 -                  key.objectid != src->i_ino)
 +                  key.objectid != btrfs_ino(src))
                        break;
  
                if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) {
                                goto next;
  
                        memcpy(&new_key, &key, sizeof(new_key));
 -                      new_key.objectid = inode->i_ino;
 +                      new_key.objectid = btrfs_ino(inode);
                        if (off <= key.offset)
                                new_key.offset = key.offset + destoff - off;
                        else
                                        ret = btrfs_inc_extent_ref(trans, root,
                                                        disko, diskl, 0,
                                                        root->root_key.objectid,
 -                                                      inode->i_ino,
 +                                                      btrfs_ino(inode),
                                                        new_key.offset - datao);
                                        BUG_ON(ret);
                                }
diff --combined fs/btrfs/transaction.c
index 4d1dbcbbaf41e5f3f166852473be5c5507868796,b83ed5e64a325553c85b0c7fff10c0a37821d8f5..8e7e7234155593770a6d7f60b3ac78506e0a1d92
@@@ -27,7 -27,6 +27,7 @@@
  #include "transaction.h"
  #include "locking.h"
  #include "tree-log.h"
 +#include "inode-map.h"
  
  #define BTRFS_ROOT_TRANS_TAG 0
  
@@@ -488,19 -487,40 +488,40 @@@ static int __btrfs_end_transaction(stru
  int btrfs_end_transaction(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root)
  {
-       return __btrfs_end_transaction(trans, root, 0, 1);
+       int ret;
+       ret = __btrfs_end_transaction(trans, root, 0, 1);
+       if (ret)
+               return ret;
+       return 0;
  }
  
  int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root)
  {
-       return __btrfs_end_transaction(trans, root, 1, 1);
+       int ret;
+       ret = __btrfs_end_transaction(trans, root, 1, 1);
+       if (ret)
+               return ret;
+       return 0;
  }
  
  int btrfs_end_transaction_nolock(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root)
  {
-       return __btrfs_end_transaction(trans, root, 0, 0);
+       int ret;
+       ret = __btrfs_end_transaction(trans, root, 0, 0);
+       if (ret)
+               return ret;
+       return 0;
+ }
+ int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root)
+ {
+       return __btrfs_end_transaction(trans, root, 1, 1);
  }
  
  /*
@@@ -761,14 -781,8 +782,14 @@@ static noinline int commit_fs_roots(str
                        btrfs_update_reloc_root(trans, root);
                        btrfs_orphan_commit_root(trans, root);
  
 +                      btrfs_save_ino_cache(root, trans);
 +
                        if (root->commit_root != root->node) {
 +                              mutex_lock(&root->fs_commit_mutex);
                                switch_commit_root(root);
 +                              btrfs_unpin_free_ino(root);
 +                              mutex_unlock(&root->fs_commit_mutex);
 +
                                btrfs_set_root_node(&root->root_item,
                                                    root->node);
                        }
@@@ -937,7 -951,7 +958,7 @@@ static noinline int create_pending_snap
                goto fail;
        }
  
 -      ret = btrfs_find_free_objectid(trans, tree_root, 0, &objectid);
 +      ret = btrfs_find_free_objectid(tree_root, &objectid);
        if (ret) {
                pending->error = ret;
                goto fail;
        BUG_ON(ret);
        ret = btrfs_insert_dir_item(trans, parent_root,
                                dentry->d_name.name, dentry->d_name.len,
-                               btrfs_ino(parent_inode), &key,
+                               parent_inode, &key,
                                BTRFS_FT_DIR, index);
        BUG_ON(ret);
  
         */
        ret = btrfs_add_root_ref(trans, tree_root, objectid,
                                 parent_root->root_key.objectid,
 -                               parent_inode->i_ino, index,
 +                               btrfs_ino(parent_inode), index,
                                 dentry->d_name.name, dentry->d_name.len);
        BUG_ON(ret);
        dput(parent);
@@@ -1044,6 -1058,14 +1065,14 @@@ static noinline int create_pending_snap
        int ret;
  
        list_for_each_entry(pending, head, list) {
+               /*
+                * We must deal with the delayed items before creating
+                * snapshots, or we will create a snapthot with inconsistent
+                * information.
+               */
+               ret = btrfs_run_delayed_items(trans, fs_info->fs_root);
+               BUG_ON(ret);
                ret = create_pending_snapshot(trans, fs_info, pending);
                BUG_ON(ret);
        }
@@@ -1297,6 -1319,9 +1326,9 @@@ int btrfs_commit_transaction(struct btr
                        BUG_ON(ret);
                }
  
+               ret = btrfs_run_delayed_items(trans, root);
+               BUG_ON(ret);
                /*
                 * rename don't use btrfs_join_transaction, so, once we
                 * set the transaction to blocked above, we aren't going
        ret = create_pending_snapshots(trans, root->fs_info);
        BUG_ON(ret);
  
+       ret = btrfs_run_delayed_items(trans, root);
+       BUG_ON(ret);
        ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
        BUG_ON(ret);
  
@@@ -1439,6 -1467,8 +1474,8 @@@ int btrfs_clean_old_snapshots(struct bt
                root = list_entry(list.next, struct btrfs_root, root_list);
                list_del(&root->root_list);
  
+               btrfs_kill_all_delayed_nodes(root);
                if (btrfs_header_backref_rev(root->node) <
                    BTRFS_MIXED_BACKREF_REV)
                        btrfs_drop_snapshot(root, NULL, 0);
diff --combined fs/btrfs/tree-log.c
index 177d943755f42f6e74ccddb5030a78624ea46cd3,ae0b72856bfb77a970dcc6966160de4d060e15d5..183913bac14ee0a3c41faa10d365728cf3e7cbd2
@@@ -519,7 -519,7 +519,7 @@@ static noinline int replay_one_extent(s
         * file.  This must be done before the btrfs_drop_extents run
         * so we don't try to drop this extent.
         */
 -      ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
 +      ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode),
                                       start, 0);
  
        if (ret == 0 &&
@@@ -832,7 -832,7 +832,7 @@@ again
        read_extent_buffer(eb, name, (unsigned long)(ref + 1), namelen);
  
        /* if we already have a perfect match, we're done */
 -      if (inode_in_dir(root, path, dir->i_ino, inode->i_ino,
 +      if (inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode),
                         btrfs_inode_ref_index(eb, ref),
                         name, namelen)) {
                goto out;
@@@ -960,9 -960,8 +960,9 @@@ static noinline int fixup_inode_link_co
        unsigned long ptr;
        unsigned long ptr_end;
        int name_len;
 +      u64 ino = btrfs_ino(inode);
  
 -      key.objectid = inode->i_ino;
 +      key.objectid = ino;
        key.type = BTRFS_INODE_REF_KEY;
        key.offset = (u64)-1;
  
                }
                btrfs_item_key_to_cpu(path->nodes[0], &key,
                                      path->slots[0]);
 -              if (key.objectid != inode->i_ino ||
 +              if (key.objectid != ino ||
                    key.type != BTRFS_INODE_REF_KEY)
                        break;
                ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]);
        if (inode->i_nlink == 0) {
                if (S_ISDIR(inode->i_mode)) {
                        ret = replay_dir_deletes(trans, root, NULL, path,
 -                                               inode->i_ino, 1);
 +                                               ino, 1);
                        BUG_ON(ret);
                }
 -              ret = insert_orphan_item(trans, root, inode->i_ino);
 +              ret = insert_orphan_item(trans, root, ino);
                BUG_ON(ret);
        }
        btrfs_free_path(path);
@@@ -2198,7 -2197,6 +2198,7 @@@ int btrfs_del_dir_entries_in_log(struc
        int ret;
        int err = 0;
        int bytes_del = 0;
 +      u64 dir_ino = btrfs_ino(dir);
  
        if (BTRFS_I(dir)->logged_trans < trans->transid)
                return 0;
                goto out_unlock;
        }
  
 -      di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino,
 +      di = btrfs_lookup_dir_item(trans, log, path, dir_ino,
                                   name, name_len, -1);
        if (IS_ERR(di)) {
                err = PTR_ERR(di);
                BUG_ON(ret);
        }
        btrfs_release_path(log, path);
 -      di = btrfs_lookup_dir_index_item(trans, log, path, dir->i_ino,
 +      di = btrfs_lookup_dir_index_item(trans, log, path, dir_ino,
                                         index, name, name_len, -1);
        if (IS_ERR(di)) {
                err = PTR_ERR(di);
        if (bytes_del) {
                struct btrfs_key key;
  
 -              key.objectid = dir->i_ino;
 +              key.objectid = dir_ino;
                key.offset = 0;
                key.type = BTRFS_INODE_ITEM_KEY;
                btrfs_release_path(log, path);
@@@ -2305,7 -2303,7 +2305,7 @@@ int btrfs_del_inode_ref_in_log(struct b
        log = root->log_root;
        mutex_lock(&BTRFS_I(inode)->log_mutex);
  
 -      ret = btrfs_del_inode_ref(trans, log, name, name_len, inode->i_ino,
 +      ret = btrfs_del_inode_ref(trans, log, name, name_len, btrfs_ino(inode),
                                  dirid, &index);
        mutex_unlock(&BTRFS_I(inode)->log_mutex);
        if (ret == -ENOSPC) {
@@@ -2371,14 -2369,13 +2371,14 @@@ static noinline int log_dir_items(struc
        int nritems;
        u64 first_offset = min_offset;
        u64 last_offset = (u64)-1;
 +      u64 ino = btrfs_ino(inode);
  
        log = root->log_root;
 -      max_key.objectid = inode->i_ino;
 +      max_key.objectid = ino;
        max_key.offset = (u64)-1;
        max_key.type = key_type;
  
 -      min_key.objectid = inode->i_ino;
 +      min_key.objectid = ino;
        min_key.type = key_type;
        min_key.offset = min_offset;
  
         * we didn't find anything from this transaction, see if there
         * is anything at all
         */
 -      if (ret != 0 || min_key.objectid != inode->i_ino ||
 -          min_key.type != key_type) {
 -              min_key.objectid = inode->i_ino;
 +      if (ret != 0 || min_key.objectid != ino || min_key.type != key_type) {
 +              min_key.objectid = ino;
                min_key.type = key_type;
                min_key.offset = (u64)-1;
                btrfs_release_path(root, path);
                        btrfs_release_path(root, path);
                        return ret;
                }
 -              ret = btrfs_previous_item(root, path, inode->i_ino, key_type);
 +              ret = btrfs_previous_item(root, path, ino, key_type);
  
                /* if ret == 0 there are items for this type,
                 * create a range to tell us the last key of this type.
        }
  
        /* go backward to find any previous key */
 -      ret = btrfs_previous_item(root, path, inode->i_ino, key_type);
 +      ret = btrfs_previous_item(root, path, ino, key_type);
        if (ret == 0) {
                struct btrfs_key tmp;
                btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]);
                for (i = path->slots[0]; i < nritems; i++) {
                        btrfs_item_key_to_cpu(src, &min_key, i);
  
 -                      if (min_key.objectid != inode->i_ino ||
 -                          min_key.type != key_type)
 +                      if (min_key.objectid != ino || min_key.type != key_type)
                                goto done;
                        ret = overwrite_item(trans, log, dst_path, src, i,
                                             &min_key);
                        goto done;
                }
                btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]);
 -              if (tmp.objectid != inode->i_ino || tmp.type != key_type) {
 +              if (tmp.objectid != ino || tmp.type != key_type) {
                        last_offset = (u64)-1;
                        goto done;
                }
@@@ -2501,7 -2500,8 +2501,7 @@@ done
                 * is valid
                 */
                ret = insert_dir_log_key(trans, log, path, key_type,
 -                                       inode->i_ino, first_offset,
 -                                       last_offset);
 +                                       ino, first_offset, last_offset);
                if (ret)
                        err = ret;
        }
@@@ -2745,7 -2745,6 +2745,7 @@@ static int btrfs_log_inode(struct btrfs
        int nritems;
        int ins_start_slot = 0;
        int ins_nr;
 +      u64 ino = btrfs_ino(inode);
  
        log = root->log_root;
  
                return -ENOMEM;
        }
  
 -      min_key.objectid = inode->i_ino;
 +      min_key.objectid = ino;
        min_key.type = BTRFS_INODE_ITEM_KEY;
        min_key.offset = 0;
  
 -      max_key.objectid = inode->i_ino;
 +      max_key.objectid = ino;
  
        /* today the code can only do partial logging of directories */
        if (!S_ISDIR(inode->i_mode))
                max_key.type = (u8)-1;
        max_key.offset = (u64)-1;
  
+       ret = btrfs_commit_inode_delayed_items(trans, inode);
+       if (ret) {
+               btrfs_free_path(path);
+               btrfs_free_path(dst_path);
+               return ret;
+       }
        mutex_lock(&BTRFS_I(inode)->log_mutex);
  
        /*
  
                if (inode_only == LOG_INODE_EXISTS)
                        max_key_type = BTRFS_XATTR_ITEM_KEY;
 -              ret = drop_objectid_items(trans, log, path,
 -                                        inode->i_ino, max_key_type);
 +              ret = drop_objectid_items(trans, log, path, ino, max_key_type);
        } else {
                ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0);
        }
                        break;
  again:
                /* note, ins_nr might be > 0 here, cleanup outside the loop */
 -              if (min_key.objectid != inode->i_ino)
 +              if (min_key.objectid != ino)
                        break;
                if (min_key.type > max_key.type)
                        break;
This page took 0.067801 seconds and 5 git commands to generate.