Merge branch 'for-chris' of git://git.kernel.org/pub/scm/linux/kernel/git/arne/btrfs...
authorChris Mason <chris.mason@oracle.com>
Mon, 23 May 2011 10:30:52 +0000 (06:30 -0400)
committerChris Mason <chris.mason@oracle.com>
Mon, 23 May 2011 10:30:52 +0000 (06:30 -0400)
Conflicts:
fs/btrfs/Makefile
fs/btrfs/ctree.h
fs/btrfs/volumes.h

Signed-off-by: Chris Mason <chris.mason@oracle.com>
12 files changed:
1  2 
fs/btrfs/Makefile
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/file-item.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/relocation.c
fs/btrfs/scrub.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h

diff --combined fs/btrfs/Makefile
@@@ -7,4 -7,4 +7,4 @@@ btrfs-y += super.o ctree.o extent-tree.
           extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
           extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
           export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \
-          compression.o delayed-ref.o relocation.o delayed-inode.o
 -         compression.o delayed-ref.o relocation.o scrub.o
++         compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o
diff --combined fs/btrfs/ctree.h
@@@ -23,6 -23,7 +23,7 @@@
  #include <linux/mm.h>
  #include <linux/highmem.h>
  #include <linux/fs.h>
+ #include <linux/rwsem.h>
  #include <linux/completion.h>
  #include <linux/backing-dev.h>
  #include <linux/wait.h>
@@@ -33,6 -34,7 +34,7 @@@
  #include "extent_io.h"
  #include "extent_map.h"
  #include "async-thread.h"
+ #include "ioctl.h"
  
  struct btrfs_trans_handle;
  struct btrfs_transaction;
@@@ -105,12 -107,6 +107,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
  
@@@ -193,7 -189,6 +195,6 @@@ struct btrfs_mapping_tree 
        struct extent_map_tree map_tree;
  };
  
- #define BTRFS_UUID_SIZE 16
  struct btrfs_dev_item {
        /* the internal btrfs device id */
        __le64 devid;
@@@ -300,7 -295,6 +301,6 @@@ static inline unsigned long btrfs_chunk
                sizeof(struct btrfs_stripe) * (num_stripes - 1);
  }
  
- #define BTRFS_FSID_SIZE 16
  #define BTRFS_HEADER_FLAG_WRITTEN     (1ULL << 0)
  #define BTRFS_HEADER_FLAG_RELOC               (1ULL << 1)
  
@@@ -516,6 -510,12 +516,12 @@@ struct btrfs_extent_item_v0 
  /* use full backrefs for extent pointers in the block */
  #define BTRFS_BLOCK_FLAG_FULL_BACKREF (1ULL << 8)
  
+ /*
+  * this flag is only used internally by scrub and may be changed at any time
+  * it is only declared here to avoid collisions
+  */
+ #define BTRFS_EXTENT_FLAG_SUPER               (1ULL << 48)
  struct btrfs_tree_block_info {
        struct btrfs_disk_key key;
        u8 level;
@@@ -724,7 -724,7 +730,7 @@@ struct btrfs_space_info 
        u64 total_bytes;        /* total bytes in the space,
                                   this doesn't take mirrors into account */
        u64 bytes_used;         /* total bytes used,
 -                                 this does't take mirrors into account */
 +                                 this doesn't take mirrors into account */
        u64 bytes_pinned;       /* total bytes pinned, will be freed when the
                                   transaction finishes */
        u64 bytes_reserved;     /* total bytes the allocator has reserved for
         */
        unsigned long reservation_progress;
  
 -      int full:1;             /* indicates that we cannot allocate any more
 +      unsigned int full:1;    /* indicates that we cannot allocate any more
                                   chunks for this space */
 -      int chunk_alloc:1;      /* set if we are allocating a chunk */
 +      unsigned int chunk_alloc:1;     /* set if we are allocating a chunk */
  
 -      int force_alloc;        /* set if we need to force a chunk alloc for
 -                                 this space */
 +      unsigned int force_alloc;       /* set if we need to force a chunk
 +                                         alloc for this space */
  
        struct list_head list;
  
@@@ -836,6 -836,9 +842,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;
  
        void *bdev_holder;
  
+       /* private scrub information */
+       struct mutex scrub_lock;
+       atomic_t scrubs_running;
+       atomic_t scrub_pause_req;
+       atomic_t scrubs_paused;
+       atomic_t scrub_cancel_req;
+       wait_queue_head_t scrub_pause_wait;
+       struct rw_semaphore scrub_super_lock;
+       int scrub_workers_refcnt;
+       struct btrfs_workers scrub_workers;
        /* filesystem state */
        u64 fs_state;
 +
 +      struct btrfs_delayed_root *delayed_root;
  };
  
  /*
@@@ -1115,16 -1124,6 +1132,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
@@@ -1463,12 -1457,26 +1480,12 @@@ static inline u64 btrfs_stripe_offset_n
        return btrfs_stripe_offset(eb, btrfs_stripe_nr(c, nr));
  }
  
 -static inline void btrfs_set_stripe_offset_nr(struct extent_buffer *eb,
 -                                           struct btrfs_chunk *c, int nr,
 -                                           u64 val)
 -{
 -      btrfs_set_stripe_offset(eb, btrfs_stripe_nr(c, nr), val);
 -}
 -
  static inline u64 btrfs_stripe_devid_nr(struct extent_buffer *eb,
                                         struct btrfs_chunk *c, int nr)
  {
        return btrfs_stripe_devid(eb, btrfs_stripe_nr(c, nr));
  }
  
 -static inline void btrfs_set_stripe_devid_nr(struct extent_buffer *eb,
 -                                           struct btrfs_chunk *c, int nr,
 -                                           u64 val)
 -{
 -      btrfs_set_stripe_devid(eb, btrfs_stripe_nr(c, nr), val);
 -}
 -
  /* struct btrfs_block_group_item */
  BTRFS_SETGET_STACK_FUNCS(block_group_used, struct btrfs_block_group_item,
                         used, 64);
@@@ -1526,6 -1534,14 +1543,6 @@@ btrfs_inode_ctime(struct btrfs_inode_it
        return (struct btrfs_timespec *)ptr;
  }
  
 -static inline struct btrfs_timespec *
 -btrfs_inode_otime(struct btrfs_inode_item *inode_item)
 -{
 -      unsigned long ptr = (unsigned long)inode_item;
 -      ptr += offsetof(struct btrfs_inode_item, otime);
 -      return (struct btrfs_timespec *)ptr;
 -}
 -
  BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64);
  BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32);
  
@@@ -1876,6 -1892,33 +1893,6 @@@ static inline u8 *btrfs_header_chunk_tr
        return (u8 *)ptr;
  }
  
 -static inline u8 *btrfs_super_fsid(struct extent_buffer *eb)
 -{
 -      unsigned long ptr = offsetof(struct btrfs_super_block, fsid);
 -      return (u8 *)ptr;
 -}
 -
 -static inline u8 *btrfs_header_csum(struct extent_buffer *eb)
 -{
 -      unsigned long ptr = offsetof(struct btrfs_header, csum);
 -      return (u8 *)ptr;
 -}
 -
 -static inline struct btrfs_node *btrfs_buffer_node(struct extent_buffer *eb)
 -{
 -      return NULL;
 -}
 -
 -static inline struct btrfs_leaf *btrfs_buffer_leaf(struct extent_buffer *eb)
 -{
 -      return NULL;
 -}
 -
 -static inline struct btrfs_header *btrfs_buffer_header(struct extent_buffer *eb)
 -{
 -      return NULL;
 -}
 -
  static inline int btrfs_is_leaf(struct extent_buffer *eb)
  {
        return btrfs_header_level(eb) == 0;
@@@ -2029,6 -2072,22 +2046,6 @@@ static inline struct btrfs_root *btrfs_
        return sb->s_fs_info;
  }
  
 -static inline int btrfs_set_root_name(struct btrfs_root *root,
 -                                    const char *name, int len)
 -{
 -      /* if we already have a name just free it */
 -      kfree(root->name);
 -
 -      root->name = kmalloc(len+1, GFP_KERNEL);
 -      if (!root->name)
 -              return -ENOMEM;
 -
 -      memcpy(root->name, name, len);
 -      root->name[len] = '\0';
 -
 -      return 0;
 -}
 -
  static inline u32 btrfs_level_size(struct btrfs_root *root, int level)
  {
        if (level == 0)
@@@ -2057,13 -2116,6 +2074,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);
@@@ -2073,9 -2125,12 +2090,9 @@@ int btrfs_lookup_extent_info(struct btr
                             u64 num_bytes, u64 *refs, u64 *flags);
  int btrfs_pin_extent(struct btrfs_root *root,
                     u64 bytenr, u64 num, int reserved);
 -int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
 -                      struct btrfs_root *root, struct extent_buffer *leaf);
  int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root,
                          u64 objectid, u64 offset, u64 bytenr);
 -int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy);
  struct btrfs_block_group_cache *btrfs_lookup_block_group(
                                                 struct btrfs_fs_info *info,
                                                 u64 bytenr);
@@@ -2252,12 -2307,10 +2269,12 @@@ int btrfs_realloc_node(struct btrfs_tra
                       struct btrfs_root *root, struct extent_buffer *parent,
                       int start_slot, int cache_only, u64 *last_ret,
                       struct btrfs_key *progress);
 -void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
 +void btrfs_release_path(struct btrfs_path *p);
  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,
@@@ -2269,12 -2322,13 +2286,12 @@@ 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,
 -                          struct btrfs_root *root,
 -                          struct btrfs_path *path,
 -                          struct btrfs_key *cpu_key, u32 *data_size,
 -                          int nr);
  int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct btrfs_path *path,
@@@ -2320,6 -2374,8 +2337,6 @@@ int btrfs_update_root(struct btrfs_tran
                      *item);
  int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct
                         btrfs_root_item *item, struct btrfs_key *key);
 -int btrfs_search_root(struct btrfs_root *root, u64 search_start,
 -                    u64 *found_objectid);
  int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid);
  int btrfs_find_orphan_roots(struct btrfs_root *tree_root);
  int btrfs_set_root_node(struct btrfs_root_item *item,
@@@ -2329,7 -2385,7 +2346,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,
@@@ -2374,6 -2430,12 +2391,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,
@@@ -2418,12 -2480,17 +2435,15 @@@ int btrfs_csum_file_blocks(struct btrfs
                           struct btrfs_ordered_sum *sums);
  int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
                       struct bio *bio, u64 file_start, int contig);
 -int btrfs_csum_file_bytes(struct btrfs_root *root, struct inode *inode,
 -                        u64 start, unsigned long len);
  struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
                                          struct btrfs_root *root,
                                          struct btrfs_path *path,
                                          u64 bytenr, int cow);
- int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start,
-                            u64 end, struct list_head *list);
+ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *root, struct btrfs_path *path,
+                       u64 isize);
+ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
+                            struct list_head *list, int search_commit);
  /* inode.c */
  
  /* RHEL and EL kernels have a patch that renames PG_checked to FsMisc */
@@@ -2452,6 -2519,8 +2472,6 @@@ int btrfs_truncate_inode_items(struct b
                               u32 min_type);
  
  int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
 -int btrfs_start_one_delalloc_inode(struct btrfs_root *root, int delay_iput,
 -                                 int sync);
  int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
                              struct extent_state **cached_state);
  int btrfs_writepages(struct address_space *mapping,
@@@ -2468,6 -2537,7 +2488,6 @@@ unsigned long btrfs_force_ra(struct add
  int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
  int btrfs_readpage(struct file *file, struct page *page);
  void btrfs_evict_inode(struct inode *inode);
 -void btrfs_put_inode(struct inode *inode);
  int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc);
  void btrfs_dirty_inode(struct inode *inode);
  struct inode *btrfs_alloc_inode(struct super_block *sb);
@@@ -2478,8 -2548,10 +2498,8 @@@ void btrfs_destroy_cachep(void)
  long btrfs_ioctl_trans_end(struct file *file);
  struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
                         struct btrfs_root *root, int *was_new);
 -int btrfs_commit_write(struct file *file, struct page *page,
 -                     unsigned from, unsigned to);
  struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
 -                                  size_t page_offset, u64 start, u64 end,
 +                                  size_t pg_offset, u64 start, u64 end,
                                    int create);
  int btrfs_update_inode(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root,
@@@ -2516,6 -2588,7 +2536,6 @@@ void btrfs_inherit_iflags(struct inode 
  int btrfs_sync_file(struct file *file, int datasync);
  int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                            int skip_pinned);
 -int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
  extern const struct file_operations btrfs_file_operations;
  int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
                       u64 start, u64 end, u64 *hint_byte, int drop_cache);
@@@ -2535,6 -2608,10 +2555,6 @@@ int btrfs_defrag_leaves(struct btrfs_tr
  /* sysfs.c */
  int btrfs_init_sysfs(void);
  void btrfs_exit_sysfs(void);
 -int btrfs_sysfs_add_super(struct btrfs_fs_info *fs);
 -int btrfs_sysfs_add_root(struct btrfs_root *root);
 -void btrfs_sysfs_del_root(struct btrfs_root *root);
 -void btrfs_sysfs_del_super(struct btrfs_fs_info *root);
  
  /* xattr.c */
  ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
@@@ -2577,4 -2654,18 +2597,18 @@@ void btrfs_reloc_pre_snapshot(struct bt
                              u64 *bytes_to_reserve);
  void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
                              struct btrfs_pending_snapshot *pending);
+ /* scrub.c */
+ int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end,
+                   struct btrfs_scrub_progress *progress, int readonly);
+ int btrfs_scrub_pause(struct btrfs_root *root);
+ int btrfs_scrub_pause_super(struct btrfs_root *root);
+ int btrfs_scrub_continue(struct btrfs_root *root);
+ int btrfs_scrub_continue_super(struct btrfs_root *root);
+ int btrfs_scrub_cancel(struct btrfs_root *root);
+ int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev);
+ int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid);
+ int btrfs_scrub_progress(struct btrfs_root *root, u64 devid,
+                        struct btrfs_scrub_progress *progress);
  #endif
diff --combined fs/btrfs/disk-io.c
@@@ -29,7 -29,6 +29,7 @@@
  #include <linux/crc32c.h>
  #include <linux/slab.h>
  #include <linux/migrate.h>
 +#include <linux/ratelimit.h>
  #include <asm/unaligned.h>
  #include "compat.h"
  #include "ctree.h"
@@@ -42,7 -41,6 +42,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);
@@@ -139,7 -137,7 +139,7 @@@ static const char *btrfs_eb_name[BTRFS_
   * that covers the entire device
   */
  static struct extent_map *btree_get_extent(struct inode *inode,
 -              struct page *page, size_t page_offset, u64 start, u64 len,
 +              struct page *page, size_t pg_offset, u64 start, u64 len,
                int create)
  {
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
        }
        read_unlock(&em_tree->lock);
  
 -      em = alloc_extent_map(GFP_NOFS);
 +      em = alloc_extent_map();
        if (!em) {
                em = ERR_PTR(-ENOMEM);
                goto out;
@@@ -256,12 -254,14 +256,12 @@@ static int csum_tree_block(struct btrfs
                        memcpy(&found, result, csum_size);
  
                        read_extent_buffer(buf, &val, 0, csum_size);
 -                      if (printk_ratelimit()) {
 -                              printk(KERN_INFO "btrfs: %s checksum verify "
 +                      printk_ratelimited(KERN_INFO "btrfs: %s checksum verify "
                                       "failed on %llu wanted %X found %X "
                                       "level %d\n",
                                       root->fs_info->sb->s_id,
                                       (unsigned long long)buf->start, val, found,
                                       btrfs_header_level(buf));
 -                      }
                        if (result != (char *)&inline_result)
                                kfree(result);
                        return 1;
@@@ -296,11 -296,13 +296,11 @@@ static int verify_parent_transid(struc
                ret = 0;
                goto out;
        }
 -      if (printk_ratelimit()) {
 -              printk("parent transid verify failed on %llu wanted %llu "
 +      printk_ratelimited("parent transid verify failed on %llu wanted %llu "
                       "found %llu\n",
                       (unsigned long long)eb->start,
                       (unsigned long long)parent_transid,
                       (unsigned long long)btrfs_header_generation(eb));
 -      }
        ret = 1;
        clear_extent_buffer_uptodate(io_tree, eb, &cached_state);
  out:
@@@ -378,7 -380,7 +378,7 @@@ static int csum_dirty_buffer(struct btr
        len = page->private >> 2;
        WARN_ON(len == 0);
  
 -      eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS);
 +      eb = alloc_extent_buffer(tree, start, len, page);
        if (eb == NULL) {
                WARN_ON(1);
                goto out;
@@@ -523,7 -525,7 +523,7 @@@ static int btree_readpage_end_io_hook(s
        len = page->private >> 2;
        WARN_ON(len == 0);
  
 -      eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS);
 +      eb = alloc_extent_buffer(tree, start, len, page);
        if (eb == NULL) {
                ret = -EIO;
                goto out;
  
        found_start = btrfs_header_bytenr(eb);
        if (found_start != start) {
 -              if (printk_ratelimit()) {
 -                      printk(KERN_INFO "btrfs bad tree block start "
 +              printk_ratelimited(KERN_INFO "btrfs bad tree block start "
                               "%llu %llu\n",
                               (unsigned long long)found_start,
                               (unsigned long long)eb->start);
 -              }
                ret = -EIO;
                goto err;
        }
                goto err;
        }
        if (check_tree_block_fsid(root, eb)) {
 -              if (printk_ratelimit()) {
 -                      printk(KERN_INFO "btrfs bad fsid on block %llu\n",
 +              printk_ratelimited(KERN_INFO "btrfs bad fsid on block %llu\n",
                               (unsigned long long)eb->start);
 -              }
                ret = -EIO;
                goto err;
        }
@@@ -644,6 -650,12 +644,6 @@@ unsigned long btrfs_async_submit_limit(
        return 256 * limit;
  }
  
 -int btrfs_congested_async(struct btrfs_fs_info *info, int iodone)
 -{
 -      return atomic_read(&info->nr_async_bios) >
 -              btrfs_async_submit_limit(info);
 -}
 -
  static void run_one_async_start(struct btrfs_work *work)
  {
        struct async_submit_bio *async;
@@@ -924,6 -936,7 +924,6 @@@ static const struct address_space_opera
        .writepages     = btree_writepages,
        .releasepage    = btree_releasepage,
        .invalidatepage = btree_invalidatepage,
 -      .sync_page      = block_sync_page,
  #ifdef CONFIG_MIGRATION
        .migratepage    = btree_migratepage,
  #endif
@@@ -951,7 -964,7 +951,7 @@@ struct extent_buffer *btrfs_find_tree_b
        struct inode *btree_inode = root->fs_info->btree_inode;
        struct extent_buffer *eb;
        eb = find_extent_buffer(&BTRFS_I(btree_inode)->io_tree,
 -                              bytenr, blocksize, GFP_NOFS);
 +                              bytenr, blocksize);
        return eb;
  }
  
@@@ -962,7 -975,7 +962,7 @@@ struct extent_buffer *btrfs_find_create
        struct extent_buffer *eb;
  
        eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->io_tree,
 -                               bytenr, blocksize, NULL, GFP_NOFS);
 +                               bytenr, blocksize, NULL);
        return eb;
  }
  
@@@ -1046,7 -1059,6 +1046,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;
  
        root->log_transid = 0;
        root->last_log_commit = 0;
        extent_io_tree_init(&root->dirty_log_pages,
 -                           fs_info->btree_inode->i_mapping, GFP_NOFS);
 +                           fs_info->btree_inode->i_mapping);
  
        memset(&root->root_key, 0, sizeof(root->root_key));
        memset(&root->root_item, 0, sizeof(root->root_item));
@@@ -1272,6 -1284,21 +1272,6 @@@ out
        return root;
  }
  
 -struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
 -                                      u64 root_objectid)
 -{
 -      struct btrfs_root *root;
 -
 -      if (root_objectid == BTRFS_ROOT_TREE_OBJECTID)
 -              return fs_info->tree_root;
 -      if (root_objectid == BTRFS_EXTENT_TREE_OBJECTID)
 -              return fs_info->extent_root;
 -
 -      root = radix_tree_lookup(&fs_info->fs_roots_radix,
 -                               (unsigned long)root_objectid);
 -      return root;
 -}
 -
  struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
                                              struct btrfs_key *location)
  {
@@@ -1300,19 -1327,6 +1300,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) {
@@@ -1356,6 -1370,41 +1356,6 @@@ fail
        return ERR_PTR(ret);
  }
  
 -struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
 -                                    struct btrfs_key *location,
 -                                    const char *name, int namelen)
 -{
 -      return btrfs_read_fs_root_no_name(fs_info, location);
 -#if 0
 -      struct btrfs_root *root;
 -      int ret;
 -
 -      root = btrfs_read_fs_root_no_name(fs_info, location);
 -      if (!root)
 -              return NULL;
 -
 -      if (root->in_sysfs)
 -              return root;
 -
 -      ret = btrfs_set_root_name(root, name, namelen);
 -      if (ret) {
 -              free_extent_buffer(root->node);
 -              kfree(root);
 -              return ERR_PTR(ret);
 -      }
 -
 -      ret = btrfs_sysfs_add_root(root);
 -      if (ret) {
 -              free_extent_buffer(root->node);
 -              kfree(root->name);
 -              kfree(root);
 -              return ERR_PTR(ret);
 -      }
 -      root->in_sysfs = 1;
 -      return root;
 -#endif
 -}
 -
  static int btrfs_congested_fn(void *congested_data, int bdi_bits)
  {
        struct btrfs_fs_info *info = (struct btrfs_fs_info *)congested_data;
        return ret;
  }
  
 -/*
 - * this unplugs every device on the box, and it is only used when page
 - * is null
 - */
 -static void __unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
 -{
 -      struct btrfs_device *device;
 -      struct btrfs_fs_info *info;
 -
 -      info = (struct btrfs_fs_info *)bdi->unplug_io_data;
 -      list_for_each_entry(device, &info->fs_devices->devices, dev_list) {
 -              if (!device->bdev)
 -                      continue;
 -
 -              bdi = blk_get_backing_dev_info(device->bdev);
 -              if (bdi->unplug_io_fn)
 -                      bdi->unplug_io_fn(bdi, page);
 -      }
 -}
 -
 -static void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
 -{
 -      struct inode *inode;
 -      struct extent_map_tree *em_tree;
 -      struct extent_map *em;
 -      struct address_space *mapping;
 -      u64 offset;
 -
 -      /* the generic O_DIRECT read code does this */
 -      if (1 || !page) {
 -              __unplug_io_fn(bdi, page);
 -              return;
 -      }
 -
 -      /*
 -       * page->mapping may change at any time.  Get a consistent copy
 -       * and use that for everything below
 -       */
 -      smp_mb();
 -      mapping = page->mapping;
 -      if (!mapping)
 -              return;
 -
 -      inode = mapping->host;
 -
 -      /*
 -       * don't do the expensive searching for a small number of
 -       * devices
 -       */
 -      if (BTRFS_I(inode)->root->fs_info->fs_devices->open_devices <= 2) {
 -              __unplug_io_fn(bdi, page);
 -              return;
 -      }
 -
 -      offset = page_offset(page);
 -
 -      em_tree = &BTRFS_I(inode)->extent_tree;
 -      read_lock(&em_tree->lock);
 -      em = lookup_extent_mapping(em_tree, offset, PAGE_CACHE_SIZE);
 -      read_unlock(&em_tree->lock);
 -      if (!em) {
 -              __unplug_io_fn(bdi, page);
 -              return;
 -      }
 -
 -      if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
 -              free_extent_map(em);
 -              __unplug_io_fn(bdi, page);
 -              return;
 -      }
 -      offset = offset - em->start;
 -      btrfs_unplug_page(&BTRFS_I(inode)->root->fs_info->mapping_tree,
 -                        em->block_start + offset, page);
 -      free_extent_map(em);
 -}
 -
  /*
   * If this fails, caller must call bdi_destroy() to get rid of the
   * bdi again.
@@@ -1389,6 -1514,8 +1389,6 @@@ static int setup_bdi(struct btrfs_fs_in
                return err;
  
        bdi->ra_pages   = default_backing_dev_info.ra_pages;
 -      bdi->unplug_io_fn       = btrfs_unplug_io_fn;
 -      bdi->unplug_io_data     = info;
        bdi->congested_fn       = btrfs_congested_fn;
        bdi->congested_data     = info;
        return 0;
@@@ -1563,7 -1690,7 +1563,7 @@@ struct btrfs_root *open_ctree(struct su
        struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root),
                                                 GFP_NOFS);
        struct btrfs_root *tree_root = btrfs_sb(sb);
 -      struct btrfs_fs_info *fs_info = tree_root->fs_info;
 +      struct btrfs_fs_info *fs_info = NULL;
        struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root),
                                                GFP_NOFS);
        struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root),
  
        struct btrfs_super_block *disk_super;
  
 -      if (!extent_root || !tree_root || !fs_info ||
 +      if (!extent_root || !tree_root || !tree_root->fs_info ||
            !chunk_root || !dev_root || !csum_root) {
                err = -ENOMEM;
                goto fail;
        }
 +      fs_info = tree_root->fs_info;
  
        ret = init_srcu_struct(&fs_info->subvol_srcu);
        if (ret) {
  
        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);
  
+       mutex_init(&fs_info->scrub_lock);
+       atomic_set(&fs_info->scrubs_running, 0);
+       atomic_set(&fs_info->scrub_pause_req, 0);
+       atomic_set(&fs_info->scrubs_paused, 0);
+       atomic_set(&fs_info->scrub_cancel_req, 0);
+       init_waitqueue_head(&fs_info->scrub_pause_wait);
+       init_rwsem(&fs_info->scrub_super_lock);
+       fs_info->scrub_workers_refcnt = 0;
+       btrfs_init_workers(&fs_info->scrub_workers, "scrub",
+                          fs_info->thread_pool_size, &fs_info->generic_worker);
        sb->s_blocksize = 4096;
        sb->s_blocksize_bits = blksize_bits(4096);
        sb->s_bdi = &fs_info->bdi;
  
        RB_CLEAR_NODE(&BTRFS_I(fs_info->btree_inode)->rb_node);
        extent_io_tree_init(&BTRFS_I(fs_info->btree_inode)->io_tree,
 -                           fs_info->btree_inode->i_mapping,
 -                           GFP_NOFS);
 -      extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree,
 -                           GFP_NOFS);
 +                           fs_info->btree_inode->i_mapping);
 +      extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree);
  
        BTRFS_I(fs_info->btree_inode)->io_tree.ops = &btree_extent_io_ops;
  
        fs_info->block_group_cache_tree = RB_ROOT;
  
        extent_io_tree_init(&fs_info->freed_extents[0],
 -                           fs_info->btree_inode->i_mapping, GFP_NOFS);
 +                           fs_info->btree_inode->i_mapping);
        extent_io_tree_init(&fs_info->freed_extents[1],
 -                           fs_info->btree_inode->i_mapping, GFP_NOFS);
 +                           fs_info->btree_inode->i_mapping);
        fs_info->pinned_extents = &fs_info->freed_extents[0];
        fs_info->do_barriers = 1;
  
        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,
@@@ -2100,9 -2228,6 +2111,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);
@@@ -2130,9 -2255,11 +2141,9 @@@ static void btrfs_end_buffer_write_sync
        if (uptodate) {
                set_buffer_uptodate(bh);
        } else {
 -              if (printk_ratelimit()) {
 -                      printk(KERN_WARNING "lost page write due to "
 +              printk_ratelimited(KERN_WARNING "lost page write due to "
                                        "I/O error on %s\n",
                                       bdevname(bh->b_bdev, b));
 -              }
                /* note, we dont' set_buffer_write_io_error because we have
                 * our own ways of dealing with the IO errors
                 */
@@@ -2367,15 -2494,12 +2378,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);
  }
@@@ -2488,6 -2610,7 +2499,7 @@@ int close_ctree(struct btrfs_root *root
        fs_info->closing = 1;
        smp_mb();
  
+       btrfs_scrub_cancel(root);
        btrfs_put_block_group_cache(fs_info);
  
        /*
         * ERROR state on disk.
         *
         * 2. when btrfs flips readonly just in btrfs_commit_super,
 -       * and in such case, btrfs cannnot write sb via btrfs_commit_super,
 +       * and in such case, btrfs cannot write sb via btrfs_commit_super,
         * and since fs_state has been set BTRFS_SUPER_FLAG_ERROR flag,
         * btrfs will cleanup all FS resources first and write sb then.
         */
        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);
@@@ -2632,29 -2753,6 +2644,29 @@@ void btrfs_btree_balance_dirty(struct b
        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
 +       * 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;
  
@@@ -2690,7 -2788,7 +2702,7 @@@ int btree_lock_page_hook(struct page *p
                goto out;
  
        len = page->private >> 2;
 -      eb = find_extent_buffer(io_tree, bytenr, len, GFP_NOFS);
 +      eb = find_extent_buffer(io_tree, bytenr, len);
        if (!eb)
                goto out;
  
diff --combined fs/btrfs/file-item.c
@@@ -193,7 -193,7 +193,7 @@@ static int __btrfs_lookup_bio_sums(stru
                        u32 item_size;
  
                        if (item)
 -                              btrfs_release_path(root, path);
 +                              btrfs_release_path(path);
                        item = btrfs_lookup_csum(NULL, root->fs_info->csum_root,
                                                 path, disk_bytenr, 0);
                        if (IS_ERR(item)) {
                                                EXTENT_NODATASUM, GFP_NOFS);
                                } else {
                                        printk(KERN_INFO "btrfs no csum found "
 -                                             "for inode %lu start %llu\n",
 -                                             inode->i_ino,
 +                                             "for inode %llu start %llu\n",
 +                                             (unsigned long long)
 +                                             btrfs_ino(inode),
                                               (unsigned long long)offset);
                                }
                                item = NULL;
 -                              btrfs_release_path(root, path);
 +                              btrfs_release_path(path);
                                goto found;
                        }
                        btrfs_item_key_to_cpu(path->nodes[0], &found_key,
@@@ -267,7 -266,7 +267,7 @@@ int btrfs_lookup_bio_sums_dio(struct bt
  }
  
  int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
-                            struct list_head *list)
+                            struct list_head *list, int search_commit)
  {
        struct btrfs_key key;
        struct btrfs_path *path;
        path = btrfs_alloc_path();
        BUG_ON(!path);
  
+       if (search_commit) {
+               path->skip_locking = 1;
+               path->reada = 2;
+               path->search_commit_root = 1;
+       }
        key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
        key.offset = start;
        key.type = BTRFS_EXTENT_CSUM_KEY;
@@@ -632,7 -637,7 +638,7 @@@ int btrfs_del_csums(struct btrfs_trans_
                        if (key.offset < bytenr)
                                break;
                }
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
        }
  out:
        btrfs_free_path(path);
@@@ -723,7 -728,7 +729,7 @@@ again
         * at this point, we know the tree has an item, but it isn't big
         * enough yet to put our csum in.  Grow it
         */
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        ret = btrfs_search_slot(trans, root, &file_key, path,
                                csum_size, 1);
        if (ret < 0)
        }
  
  insert:
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        csum_offset = 0;
        if (found_next) {
                u64 tmp = total_bytes + root->sectorsize;
@@@ -851,7 -856,7 +857,7 @@@ next_sector
        }
        btrfs_mark_buffer_dirty(path->nodes[0]);
        if (total_bytes < sums->len) {
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
                cond_resched();
                goto again;
        }
diff --combined fs/btrfs/inode.c
@@@ -37,7 -37,6 +37,7 @@@
  #include <linux/posix_acl.h>
  #include <linux/falloc.h>
  #include <linux/slab.h>
 +#include <linux/ratelimit.h>
  #include "compat.h"
  #include "ctree.h"
  #include "disk-io.h"
@@@ -52,7 -51,6 +52,7 @@@
  #include "compression.h"
  #include "locking.h"
  #include "free-space-cache.h"
 +#include "inode-map.h"
  
  struct btrfs_iget_args {
        u64 ino;
@@@ -95,14 -93,13 +95,14 @@@ static noinline int cow_file_range(stru
                                   unsigned long *nr_written, int unlock);
  
  static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
 -                                   struct inode *inode,  struct inode *dir)
 +                                   struct inode *inode,  struct inode *dir,
 +                                   const struct qstr *qstr)
  {
        int err;
  
        err = btrfs_init_acl(trans, inode, dir);
        if (!err)
 -              err = btrfs_xattr_security_init(trans, inode, dir);
 +              err = btrfs_xattr_security_init(trans, inode, dir, qstr);
        return err;
  }
  
@@@ -140,7 -137,7 +140,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);
@@@ -651,7 -648,7 +651,7 @@@ retry
                                        async_extent->start +
                                        async_extent->ram_size - 1, 0);
  
 -              em = alloc_extent_map(GFP_NOFS);
 +              em = alloc_extent_map();
                BUG_ON(!em);
                em->start = async_extent->start;
                em->len = async_extent->ram_size;
@@@ -747,15 -744,6 +747,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
@@@ -788,7 -776,7 +788,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);
                                           (u64)-1, &ins, 1);
                BUG_ON(ret);
  
 -              em = alloc_extent_map(GFP_NOFS);
 +              em = alloc_extent_map();
                BUG_ON(!em);
                em->start = start;
                em->orig_start = em->start;
@@@ -1019,7 -1007,7 +1019,7 @@@ static noinline int csum_exist_in_range
        LIST_HEAD(list);
  
        ret = btrfs_lookup_csums_range(root->fs_info->csum_root, bytenr,
-                                      bytenr + num_bytes - 1, &list);
+                                      bytenr + num_bytes - 1, &list, 0);
        if (ret == 0 && list_empty(&list))
                return 0;
  
@@@ -1060,31 -1048,29 +1060,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]--;
                }
@@@ -1105,7 -1091,7 +1105,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;
@@@ -1177,7 -1163,7 +1177,7 @@@ out_check
                        goto next_slot;
                }
  
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
                if (cow_start != (u64)-1) {
                        ret = cow_file_range(inode, locked_page, cow_start,
                                        found_key.offset - 1, page_started,
                        struct extent_map *em;
                        struct extent_map_tree *em_tree;
                        em_tree = &BTRFS_I(inode)->extent_tree;
 -                      em = alloc_extent_map(GFP_NOFS);
 +                      em = alloc_extent_map();
                        BUG_ON(!em);
                        em->start = cur_offset;
                        em->orig_start = em->start;
                if (cur_offset > end)
                        break;
        }
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
  
        if (cur_offset <= end && cow_start == (u64)-1)
                cow_start = cur_offset;
@@@ -1329,7 -1315,8 +1329,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;
@@@ -1362,7 -1349,8 +1362,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;
@@@ -1469,7 -1457,7 +1469,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);
@@@ -1655,7 -1643,7 +1655,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);
  
@@@ -1712,7 -1700,7 +1712,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));
@@@ -1866,7 -1854,7 +1866,7 @@@ static int btrfs_io_failed_hook(struct 
                }
                read_unlock(&em_tree->lock);
  
 -              if (!em || IS_ERR(em)) {
 +              if (IS_ERR_OR_NULL(em)) {
                        kfree(failrec);
                        return -EIO;
                }
@@@ -2015,11 -2003,12 +2015,11 @@@ good
        return 0;
  
  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_ratelimited(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);
 -      }
        memset(kaddr + offset, 1, end - start + 1);
        flush_dcache_page(page);
        kunmap_atomic(kaddr, KM_USER0);
@@@ -2254,7 -2243,7 +2254,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);
        }
  
@@@ -2291,7 -2280,7 +2291,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);
        }
  
@@@ -2335,7 -2324,7 +2335,7 @@@ int btrfs_orphan_cleanup(struct btrfs_r
  
                /*
                 * if ret == 0 means we found what we were searching for, which
 -               * is weird, but possible, so only screw with path if we didnt
 +               * is weird, but possible, so only screw with path if we didn't
                 * find the key and see if we have stuff that matches
                 */
                if (ret > 0) {
                        break;
  
                /* release the path since we're done with it */
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
  
                /*
                 * this is where we are basically btrfs_lookup, without the
@@@ -2553,8 -2542,7 +2553,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);
  
@@@ -2658,26 -2646,11 +2658,26 @@@ noinline int btrfs_update_inode(struct 
        struct extent_buffer *leaf;
        int ret;
  
 +      /*
 +       * 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);
@@@ -2698,6 -2671,7 +2698,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
@@@ -2714,8 -2688,6 +2714,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);
        ret = btrfs_delete_one_dir_name(trans, root, path, di);
        if (ret)
                goto err;
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(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->i_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,
@@@ -2833,14 -2815,12 +2833,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 */
        } else {
                check_link = 0;
        }
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
  
        ret = btrfs_lookup_inode(trans, root, path,
                                &BTRFS_I(inode)->location, 0);
        } else {
                check_link = 0;
        }
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
  
        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;
                BUG_ON(ret == 0);
                if (check_path_shared(root, path))
                        goto out;
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
        }
  
        if (!check_link) {
                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);
                err = 0;
                goto out;
        }
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
  
        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;
        if (check_path_shared(root, path))
                goto out;
        index = btrfs_inode_ref_index(path->nodes[0], ref);
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(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);
@@@ -3026,47 -2998,54 +3026,47 @@@ 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));
 +      BUG_ON(IS_ERR_OR_NULL(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);
        BUG_ON(ret);
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
  
        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));
 +              BUG_ON(IS_ERR_OR_NULL(di));
  
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
                index = key.offset;
        }
 +      btrfs_release_path(path);
  
 -      di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_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;
  }
  
@@@ -3079,7 -3058,7 +3079,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,
        return err;
  }
  
 -#if 0
 -/*
 - * when truncating bytes in a file, it is possible to avoid reading
 - * the leaves that contain only checksum items.  This can be the
 - * majority of the IO required to delete a large file, but it must
 - * be done carefully.
 - *
 - * The keys in the level just above the leaves are checked to make sure
 - * the lowest key in a given leaf is a csum key, and starts at an offset
 - * after the new  size.
 - *
 - * Then the key for the next leaf is checked to make sure it also has
 - * a checksum item for the same file.  If it does, we know our target leaf
 - * contains only checksum items, and it can be safely freed without reading
 - * it.
 - *
 - * This is just an optimization targeted at large files.  It may do
 - * nothing.  It will return 0 unless things went badly.
 - */
 -static noinline int drop_csum_leaves(struct btrfs_trans_handle *trans,
 -                                   struct btrfs_root *root,
 -                                   struct btrfs_path *path,
 -                                   struct inode *inode, u64 new_size)
 -{
 -      struct btrfs_key key;
 -      int ret;
 -      int nritems;
 -      struct btrfs_key found_key;
 -      struct btrfs_key other_key;
 -      struct btrfs_leaf_ref *ref;
 -      u64 leaf_gen;
 -      u64 leaf_start;
 -
 -      path->lowest_level = 1;
 -      key.objectid = inode->i_ino;
 -      key.type = BTRFS_CSUM_ITEM_KEY;
 -      key.offset = new_size;
 -again:
 -      ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
 -      if (ret < 0)
 -              goto out;
 -
 -      if (path->nodes[1] == NULL) {
 -              ret = 0;
 -              goto out;
 -      }
 -      ret = 0;
 -      btrfs_node_key_to_cpu(path->nodes[1], &found_key, path->slots[1]);
 -      nritems = btrfs_header_nritems(path->nodes[1]);
 -
 -      if (!nritems)
 -              goto out;
 -
 -      if (path->slots[1] >= nritems)
 -              goto next_node;
 -
 -      /* did we find a key greater than anything we want to delete? */
 -      if (found_key.objectid > inode->i_ino ||
 -         (found_key.objectid == inode->i_ino && found_key.type > key.type))
 -              goto out;
 -
 -      /* we check the next key in the node to make sure the leave contains
 -       * only checksum items.  This comparison doesn't work if our
 -       * leaf is the last one in the node
 -       */
 -      if (path->slots[1] + 1 >= nritems) {
 -next_node:
 -              /* search forward from the last key in the node, this
 -               * will bring us into the next node in the tree
 -               */
 -              btrfs_node_key_to_cpu(path->nodes[1], &found_key, nritems - 1);
 -
 -              /* unlikely, but we inc below, so check to be safe */
 -              if (found_key.offset == (u64)-1)
 -                      goto out;
 -
 -              /* search_forward needs a path with locks held, do the
 -               * search again for the original key.  It is possible
 -               * this will race with a balance and return a path that
 -               * we could modify, but this drop is just an optimization
 -               * and is allowed to miss some leaves.
 -               */
 -              btrfs_release_path(root, path);
 -              found_key.offset++;
 -
 -              /* setup a max key for search_forward */
 -              other_key.offset = (u64)-1;
 -              other_key.type = key.type;
 -              other_key.objectid = key.objectid;
 -
 -              path->keep_locks = 1;
 -              ret = btrfs_search_forward(root, &found_key, &other_key,
 -                                         path, 0, 0);
 -              path->keep_locks = 0;
 -              if (ret || found_key.objectid != key.objectid ||
 -                  found_key.type != key.type) {
 -                      ret = 0;
 -                      goto out;
 -              }
 -
 -              key.offset = found_key.offset;
 -              btrfs_release_path(root, path);
 -              cond_resched();
 -              goto again;
 -      }
 -
 -      /* we know there's one more slot after us in the tree,
 -       * read that key so we can verify it is also a checksum item
 -       */
 -      btrfs_node_key_to_cpu(path->nodes[1], &other_key, path->slots[1] + 1);
 -
 -      if (found_key.objectid < inode->i_ino)
 -              goto next_key;
 -
 -      if (found_key.type != key.type || found_key.offset < new_size)
 -              goto next_key;
 -
 -      /*
 -       * if the key for the next leaf isn't a csum key from this objectid,
 -       * we can't be sure there aren't good items inside this leaf.
 -       * Bail out
 -       */
 -      if (other_key.objectid != inode->i_ino || other_key.type != key.type)
 -              goto out;
 -
 -      leaf_start = btrfs_node_blockptr(path->nodes[1], path->slots[1]);
 -      leaf_gen = btrfs_node_ptr_generation(path->nodes[1], path->slots[1]);
 -      /*
 -       * it is safe to delete this leaf, it contains only
 -       * csum items from this inode at an offset >= new_size
 -       */
 -      ret = btrfs_del_leaf(trans, root, path, leaf_start);
 -      BUG_ON(ret);
 -
 -      if (root->ref_cows && leaf_gen < trans->transid) {
 -              ref = btrfs_alloc_leaf_ref(root, 0);
 -              if (ref) {
 -                      ref->root_gen = root->root_key.offset;
 -                      ref->bytenr = leaf_start;
 -                      ref->owner = 0;
 -                      ref->generation = leaf_gen;
 -                      ref->nritems = 0;
 -
 -                      btrfs_sort_leaf_ref(ref);
 -
 -                      ret = btrfs_add_leaf_ref(root, ref, 0);
 -                      WARN_ON(ret);
 -                      btrfs_free_leaf_ref(root, ref);
 -              } else {
 -                      WARN_ON(1);
 -              }
 -      }
 -next_key:
 -      btrfs_release_path(root, path);
 -
 -      if (other_key.objectid == inode->i_ino &&
 -          other_key.type == key.type && other_key.offset > key.offset) {
 -              key.offset = other_key.offset;
 -              cond_resched();
 -              goto again;
 -      }
 -      ret = 0;
 -out:
 -      /* fixup any changes we've made to the path */
 -      path->lowest_level = 0;
 -      path->keep_locks = 0;
 -      btrfs_release_path(root, path);
 -      return ret;
 -}
 -
 -#endif
 -
  /*
   * this can truncate away extent items, csum items and directory items.
   * It starts at a high offset and removes keys until it can't find
@@@ -3148,27 -3299,17 +3148,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;
  
@@@ -3196,7 -3337,7 +3196,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)
@@@ -3315,7 -3456,7 +3315,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;
                        }
                                BUG_ON(ret);
                                pending_del_nr = 0;
                        }
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        goto search_again;
                } else {
                        path->slots[0]--;
@@@ -3495,7 -3634,7 +3495,7 @@@ int btrfs_cont_expand(struct inode *ino
        while (1) {
                em = btrfs_get_extent(inode, NULL, 0, cur_offset,
                                block_end - cur_offset, 0);
 -              BUG_ON(IS_ERR(em) || !em);
 +              BUG_ON(IS_ERR_OR_NULL(em));
                last_byte = min(extent_map_end(em), block_end);
                last_byte = (last_byte + mask) & ~mask;
                if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
                                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)
@@@ -3618,7 -3757,7 +3618,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);
@@@ -3700,12 -3835,12 +3700,12 @@@ 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);
  
 -      if (!di || IS_ERR(di))
 +      if (IS_ERR_OR_NULL(di))
                goto out_err;
  
        btrfs_dir_item_key_to_cpu(path->nodes[0], di, location);
@@@ -3753,7 -3888,7 +3753,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;
  
        if (ret)
                goto out;
  
 -      btrfs_release_path(root->fs_info->tree_root, path);
 +      btrfs_release_path(path);
  
        new_root = btrfs_read_fs_root_no_name(root->fs_info, location);
        if (IS_ERR(new_root)) {
@@@ -3792,7 -3927,6 +3792,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 &
@@@ -3871,9 -4005,9 +3871,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);
@@@ -3928,7 -4062,7 +3928,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;
  }
  
@@@ -4073,7 -4207,7 +4073,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
  };
  
@@@ -4087,8 -4221,6 +4087,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;
@@@ -4224,15 -4344,6 +4224,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;
  }
@@@ -4262,8 -4371,7 +4262,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)
@@@ -4306,25 -4414,25 +4306,25 @@@ void btrfs_dirty_inode(struct inode *in
                btrfs_end_transaction(trans, root);
                trans = btrfs_start_transaction(root, 1);
                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));
 -                      }
 +                      printk_ratelimited(KERN_ERR "btrfs: fail to "
 +                                     "dirty  inode %llu error %ld\n",
 +                                     (unsigned long long)btrfs_ino(inode),
 +                                     PTR_ERR(trans));
                        return;
                }
                btrfs_set_trans_block_group(trans, inode);
  
                ret = btrfs_update_inode(trans, root, inode);
                if (ret) {
 -                      if (printk_ratelimit()) {
 -                              printk(KERN_ERR "btrfs: fail to "
 -                                     "dirty  inode %lu error %d\n",
 -                                     inode->i_ino, ret);
 -                      }
 +                      printk_ratelimited(KERN_ERR "btrfs: fail to "
 +                                     "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);
  }
  
  /*
@@@ -4340,7 -4448,7 +4340,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;
@@@ -4393,12 -4501,9 +4393,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;
@@@ -4434,12 -4539,6 +4434,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],
@@@ -4548,29 -4648,29 +4548,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_inode->i_ino, &key,
 +                                          parent_inode, &key,
                                            btrfs_inode_type(inode), index);
                BUG_ON(ret);
  
@@@ -4613,6 -4713,10 +4613,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);
                goto out_unlock;
        }
  
 -      err = btrfs_init_inode_security(trans, inode, dir);
 +      err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err) {
                drop_inode = 1;
                goto out_unlock;
@@@ -4676,6 -4776,9 +4676,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);
                goto out_unlock;
        }
  
 -      err = btrfs_init_inode_security(trans, inode, dir);
 +      err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err) {
                drop_inode = 1;
                goto out_unlock;
@@@ -4740,6 -4839,9 +4740,6 @@@ static int btrfs_link(struct dentry *ol
        int err;
        int drop_inode = 0;
  
 -      if (inode->i_nlink == 0)
 -              return -ENOENT;
 -
        /* do not allow sys_link's with other subvols of the same device */
        if (root->objectid != BTRFS_I(inode)->root->objectid)
                return -EXDEV;
@@@ -4803,6 -4905,10 +4803,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)) {
  
        drop_on_err = 1;
  
 -      err = btrfs_init_inode_security(trans, inode, dir);
 +      err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err)
                goto out_fail;
  
@@@ -4941,7 -5043,7 +4941,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;
@@@ -4969,7 -5071,7 +4969,7 @@@ again
                else
                        goto out;
        }
 -      em = alloc_extent_map(GFP_NOFS);
 +      em = alloc_extent_map();
        if (!em) {
                err = -ENOMEM;
                goto out;
                                kunmap(page);
                                free_extent_map(em);
                                em = NULL;
 -                              btrfs_release_path(root, path);
 +                              btrfs_release_path(path);
                                trans = btrfs_join_transaction(root, 1);
                                if (IS_ERR(trans))
                                        return ERR_CAST(trans);
@@@ -5149,7 -5251,7 +5149,7 @@@ not_found_em
        em->block_start = EXTENT_MAP_HOLE;
        set_bit(EXTENT_FLAG_VACANCY, &em->flags);
  insert:
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        if (em->start > start || extent_map_end(em) <= start) {
                printk(KERN_ERR "Btrfs: bad extent! em: [%llu %llu] passed "
                       "[%llu %llu]\n", (unsigned long long)em->start,
@@@ -5282,7 -5384,7 +5282,7 @@@ struct extent_map *btrfs_get_extent_fie
                u64 hole_start = start;
                u64 hole_len = len;
  
 -              em = alloc_extent_map(GFP_NOFS);
 +              em = alloc_extent_map();
                if (!em) {
                        err = -ENOMEM;
                        goto out;
@@@ -5383,7 -5485,7 +5383,7 @@@ static struct extent_map *btrfs_new_ext
        }
  
        if (!em) {
 -              em = alloc_extent_map(GFP_NOFS);
 +              em = alloc_extent_map();
                if (!em) {
                        em = ERR_PTR(-ENOMEM);
                        goto out;
@@@ -5449,7 -5551,7 +5449,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;
  
@@@ -5690,10 -5792,9 +5690,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;
                        }
@@@ -5840,9 -5941,9 +5840,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;
  
@@@ -6685,12 -6786,10 +6685,12 @@@ 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);
 -      extent_io_tree_init(&ei->io_failure_tree, &inode->i_data, GFP_NOFS);
 +      extent_map_tree_init(&ei->extent_tree);
 +      extent_io_tree_init(&ei->io_tree, &inode->i_data);
 +      extent_io_tree_init(&ei->io_failure_tree, &inode->i_data);
        mutex_init(&ei->log_mutex);
        btrfs_ordered_inode_tree_init(&ei->ordered_tree);
        INIT_LIST_HEAD(&ei->i_orphan);
@@@ -6754,8 -6853,8 +6754,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);
  }
  
@@@ -6786,7 -6884,7 +6786,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);
@@@ -6895,17 -6993,16 +6895,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;
@@@ -7088,6 -7187,58 +7088,6 @@@ int btrfs_start_delalloc_inodes(struct 
        return 0;
  }
  
 -int btrfs_start_one_delalloc_inode(struct btrfs_root *root, int delay_iput,
 -                                 int sync)
 -{
 -      struct btrfs_inode *binode;
 -      struct inode *inode = NULL;
 -
 -      spin_lock(&root->fs_info->delalloc_lock);
 -      while (!list_empty(&root->fs_info->delalloc_inodes)) {
 -              binode = list_entry(root->fs_info->delalloc_inodes.next,
 -                                  struct btrfs_inode, delalloc_inodes);
 -              inode = igrab(&binode->vfs_inode);
 -              if (inode) {
 -                      list_move_tail(&binode->delalloc_inodes,
 -                                     &root->fs_info->delalloc_inodes);
 -                      break;
 -              }
 -
 -              list_del_init(&binode->delalloc_inodes);
 -              cond_resched_lock(&root->fs_info->delalloc_lock);
 -      }
 -      spin_unlock(&root->fs_info->delalloc_lock);
 -
 -      if (inode) {
 -              if (sync) {
 -                      filemap_write_and_wait(inode->i_mapping);
 -                      /*
 -                       * We have to do this because compression doesn't
 -                       * actually set PG_writeback until it submits the pages
 -                       * for IO, which happens in an async thread, so we could
 -                       * race and not actually wait for any writeback pages
 -                       * because they've not been submitted yet.  Technically
 -                       * this could still be the case for the ordered stuff
 -                       * since the async thread may not have started to do its
 -                       * work yet.  If this becomes the case then we need to
 -                       * figure out a way to make sure that in writepage we
 -                       * wait for any async pages to be submitted before
 -                       * returning so that fdatawait does what its supposed to
 -                       * do.
 -                       */
 -                      btrfs_wait_ordered_range(inode, 0, (u64)-1);
 -              } else {
 -                      filemap_flush(inode->i_mapping);
 -              }
 -              if (delay_iput)
 -                      btrfs_add_delayed_iput(inode);
 -              else
 -                      iput(inode);
 -              return 1;
 -      }
 -      return 0;
 -}
 -
  static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
                         const char *symname)
  {
        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)) {
                goto out_unlock;
        }
  
 -      err = btrfs_init_inode_security(trans, inode, dir);
 +      err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err) {
                drop_inode = 1;
                goto out_unlock;
  
        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);
@@@ -7371,6 -7521,7 +7371,6 @@@ static const struct address_space_opera
        .writepage      = btrfs_writepage,
        .writepages     = btrfs_writepages,
        .readpages      = btrfs_readpages,
 -      .sync_page      = block_sync_page,
        .direct_IO      = btrfs_direct_IO,
        .invalidatepage = btrfs_invalidatepage,
        .releasepage    = btrfs_releasepage,
diff --combined fs/btrfs/ioctl.c
@@@ -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)
@@@ -82,13 -81,6 +82,13 @@@ static unsigned int btrfs_flags_to_ioct
                iflags |= FS_NOATIME_FL;
        if (flags & BTRFS_INODE_DIRSYNC)
                iflags |= FS_DIRSYNC_FL;
 +      if (flags & BTRFS_INODE_NODATACOW)
 +              iflags |= FS_NOCOW_FL;
 +
 +      if ((flags & BTRFS_INODE_COMPRESS) && !(flags & BTRFS_INODE_NOCOMPRESS))
 +              iflags |= FS_COMPR_FL;
 +      else if (flags & BTRFS_INODE_NOCOMPRESS)
 +              iflags |= FS_NOCOMP_FL;
  
        return iflags;
  }
@@@ -152,13 -144,16 +152,13 @@@ static int check_flags(unsigned int fla
        if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
                      FS_NOATIME_FL | FS_NODUMP_FL | \
                      FS_SYNC_FL | FS_DIRSYNC_FL | \
 -                    FS_NOCOMP_FL | FS_COMPR_FL | \
 -                    FS_NOCOW_FL | FS_COW_FL))
 +                    FS_NOCOMP_FL | FS_COMPR_FL |
 +                    FS_NOCOW_FL))
                return -EOPNOTSUPP;
  
        if ((flags & FS_NOCOMP_FL) && (flags & FS_COMPR_FL))
                return -EINVAL;
  
 -      if ((flags & FS_NOCOW_FL) && (flags & FS_COW_FL))
 -              return -EINVAL;
 -
        return 0;
  }
  
@@@ -181,7 -176,7 +181,7 @@@ static int btrfs_ioctl_setflags(struct 
        if (ret)
                return ret;
  
 -      if (!is_owner_or_cap(inode))
 +      if (!inode_owner_or_capable(inode))
                return -EACCES;
  
        mutex_lock(&inode->i_mutex);
                ip->flags |= BTRFS_INODE_DIRSYNC;
        else
                ip->flags &= ~BTRFS_INODE_DIRSYNC;
 +      if (flags & FS_NOCOW_FL)
 +              ip->flags |= BTRFS_INODE_NODATACOW;
 +      else
 +              ip->flags &= ~BTRFS_INODE_NODATACOW;
  
        /*
         * The COMPRESS flag can only be changed by users, while the NOCOMPRESS
        } else if (flags & FS_COMPR_FL) {
                ip->flags |= BTRFS_INODE_COMPRESS;
                ip->flags &= ~BTRFS_INODE_NOCOMPRESS;
 +      } else {
 +              ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
        }
 -      if (flags & FS_NOCOW_FL)
 -              ip->flags |= BTRFS_INODE_NODATACOW;
 -      else if (flags & FS_COW_FL)
 -              ip->flags &= ~BTRFS_INODE_NODATACOW;
  
        trans = btrfs_join_transaction(root, 1);
        BUG_ON(IS_ERR(trans));
@@@ -330,7 -323,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, dir->i_ino, &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 -1123,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 -1150,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)))
        if (flags & ~BTRFS_SUBVOL_RDONLY)
                return -EOPNOTSUPP;
  
 -      if (!is_owner_or_cap(inode))
 +      if (!inode_owner_or_capable(inode))
                return -EACCES;
  
        down_write(&root->fs_info->subvol_sem);
@@@ -1402,7 -1396,7 +1402,7 @@@ static noinline int search_ioctl(struc
                }
                ret = copy_to_sk(root, path, &key, sk, args->buf,
                                 &sk_offset, &num_found);
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
                if (ret || num_found >= sk->nr_items)
                        break;
  
@@@ -1509,7 -1503,7 +1509,7 @@@ static noinline int btrfs_search_path_i
                if (key.offset == BTRFS_FIRST_FREE_OBJECTID)
                        break;
  
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
                key.objectid = key.offset;
                key.offset = (u64)-1;
                dirid = key.objectid;
@@@ -1639,7 -1633,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;
        }
@@@ -1809,6 -1803,75 +1809,75 @@@ static long btrfs_ioctl_rm_dev(struct b
        return ret;
  }
  
+ static long btrfs_ioctl_fs_info(struct btrfs_root *root, void __user *arg)
+ {
+       struct btrfs_ioctl_fs_info_args fi_args;
+       struct btrfs_device *device;
+       struct btrfs_device *next;
+       struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       fi_args.num_devices = fs_devices->num_devices;
+       fi_args.max_id = 0;
+       memcpy(&fi_args.fsid, root->fs_info->fsid, sizeof(fi_args.fsid));
+       mutex_lock(&fs_devices->device_list_mutex);
+       list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
+               if (device->devid > fi_args.max_id)
+                       fi_args.max_id = device->devid;
+       }
+       mutex_unlock(&fs_devices->device_list_mutex);
+       if (copy_to_user(arg, &fi_args, sizeof(fi_args)))
+               return -EFAULT;
+       return 0;
+ }
+ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
+ {
+       struct btrfs_ioctl_dev_info_args *di_args;
+       struct btrfs_device *dev;
+       struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
+       int ret = 0;
+       char *s_uuid = NULL;
+       char empty_uuid[BTRFS_UUID_SIZE] = {0};
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       di_args = memdup_user(arg, sizeof(*di_args));
+       if (IS_ERR(di_args))
+               return PTR_ERR(di_args);
+       if (memcmp(empty_uuid, di_args->uuid, BTRFS_UUID_SIZE) != 0)
+               s_uuid = di_args->uuid;
+       mutex_lock(&fs_devices->device_list_mutex);
+       dev = btrfs_find_device(root, di_args->devid, s_uuid, NULL);
+       mutex_unlock(&fs_devices->device_list_mutex);
+       if (!dev) {
+               ret = -ENODEV;
+               goto out;
+       }
+       di_args->devid = dev->devid;
+       di_args->bytes_used = dev->bytes_used;
+       di_args->total_bytes = dev->total_bytes;
+       memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid));
+       strncpy(di_args->path, dev->name, sizeof(di_args->path));
+ out:
+       if (ret == 0 && copy_to_user(arg, di_args, sizeof(*di_args)))
+               ret = -EFAULT;
+       kfree(di_args);
+       return ret;
+ }
  static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                       u64 off, u64 olen, u64 destoff)
  {
        }
  
        /* 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) {
                                datal = btrfs_file_extent_ram_bytes(leaf,
                                                                    extent);
                        }
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
  
                        if (key.offset + datal <= off ||
                            key.offset >= off+len)
                                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);
                                }
                        }
  
                        btrfs_mark_buffer_dirty(leaf);
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
  
                        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
  
                        btrfs_end_transaction(trans, root);
                }
  next:
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
                key.offset++;
        }
        ret = 0;
  out:
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS);
  out_unlock:
        mutex_unlock(&src->i_mutex);
@@@ -2471,6 -2534,58 +2540,58 @@@ static noinline long btrfs_ioctl_wait_s
        return btrfs_wait_for_commit(root, transid);
  }
  
+ static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg)
+ {
+       int ret;
+       struct btrfs_ioctl_scrub_args *sa;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       sa = memdup_user(arg, sizeof(*sa));
+       if (IS_ERR(sa))
+               return PTR_ERR(sa);
+       ret = btrfs_scrub_dev(root, sa->devid, sa->start, sa->end,
+                             &sa->progress, sa->flags & BTRFS_SCRUB_READONLY);
+       if (copy_to_user(arg, sa, sizeof(*sa)))
+               ret = -EFAULT;
+       kfree(sa);
+       return ret;
+ }
+ static long btrfs_ioctl_scrub_cancel(struct btrfs_root *root, void __user *arg)
+ {
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       return btrfs_scrub_cancel(root);
+ }
+ static long btrfs_ioctl_scrub_progress(struct btrfs_root *root,
+                                      void __user *arg)
+ {
+       struct btrfs_ioctl_scrub_args *sa;
+       int ret;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       sa = memdup_user(arg, sizeof(*sa));
+       if (IS_ERR(sa))
+               return PTR_ERR(sa);
+       ret = btrfs_scrub_progress(root, sa->devid, &sa->progress);
+       if (copy_to_user(arg, sa, sizeof(*sa)))
+               ret = -EFAULT;
+       kfree(sa);
+       return ret;
+ }
  long btrfs_ioctl(struct file *file, unsigned int
                cmd, unsigned long arg)
  {
                return btrfs_ioctl_add_dev(root, argp);
        case BTRFS_IOC_RM_DEV:
                return btrfs_ioctl_rm_dev(root, argp);
+       case BTRFS_IOC_FS_INFO:
+               return btrfs_ioctl_fs_info(root, argp);
+       case BTRFS_IOC_DEV_INFO:
+               return btrfs_ioctl_dev_info(root, argp);
        case BTRFS_IOC_BALANCE:
                return btrfs_balance(root->fs_info->dev_root);
        case BTRFS_IOC_CLONE:
                return btrfs_ioctl_start_sync(file, argp);
        case BTRFS_IOC_WAIT_SYNC:
                return btrfs_ioctl_wait_sync(file, argp);
+       case BTRFS_IOC_SCRUB:
+               return btrfs_ioctl_scrub(root, argp);
+       case BTRFS_IOC_SCRUB_CANCEL:
+               return btrfs_ioctl_scrub_cancel(root, argp);
+       case BTRFS_IOC_SCRUB_PROGRESS:
+               return btrfs_ioctl_scrub_progress(root, argp);
        }
  
        return -ENOTTY;
diff --combined fs/btrfs/relocation.c
@@@ -30,7 -30,6 +30,7 @@@
  #include "btrfs_inode.h"
  #include "async-thread.h"
  #include "free-space-cache.h"
 +#include "inode-map.h"
  
  /*
   * backref_node, mapping_node and tree_block start with this
@@@ -508,7 -507,6 +508,7 @@@ static int update_backref_cache(struct 
        return 1;
  }
  
 +
  static int should_ignore_root(struct btrfs_root *root)
  {
        struct btrfs_root *reloc_root;
         */
        return 1;
  }
 -
  /*
   * find reloc tree by address of tree root
   */
@@@ -962,7 -961,7 +962,7 @@@ again
                        lower = upper;
                        upper = NULL;
                }
 -              btrfs_release_path(root, path2);
 +              btrfs_release_path(path2);
  next:
                if (ptr < end) {
                        ptr += btrfs_extent_inline_ref_size(key.type);
                if (ptr >= end)
                        path1->slots[0]++;
        }
 -      btrfs_release_path(rc->extent_root, path1);
 +      btrfs_release_path(path1);
  
        cur->checked = 1;
        WARN_ON(exist);
@@@ -1410,9 -1409,9 +1410,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;
                        }
                        return inode;
                }
  
 -              objectid = entry->vfs_inode.i_ino + 1;
 +              objectid = btrfs_ino(&entry->vfs_inode) + 1;
                if (cond_resched_lock(&root->inode_lock))
                        goto again;
  
@@@ -1471,7 -1470,7 +1471,7 @@@ static int get_new_location(struct inod
                return -ENOMEM;
  
        bytenr -= BTRFS_I(reloc_inode)->index_cnt;
 -      ret = btrfs_lookup_file_extent(NULL, root, path, reloc_inode->i_ino,
 +      ret = btrfs_lookup_file_extent(NULL, root, path, btrfs_ino(reloc_inode),
                                       bytenr, 0);
        if (ret < 0)
                goto out;
@@@ -1559,11 -1558,11 +1559,11 @@@ int replace_file_extents(struct btrfs_t
                        if (first) {
                                inode = find_next_inode(root, key.objectid);
                                first = 0;
 -                      } else if (inode && inode->i_ino < key.objectid) {
 +                      } else if (inode && btrfs_ino(inode) < key.objectid) {
                                btrfs_add_delayed_iput(inode);
                                inode = find_next_inode(root, key.objectid);
                        }
 -                      if (inode && inode->i_ino == key.objectid) {
 +                      if (inode && btrfs_ino(inode) == key.objectid) {
                                end = key.offset +
                                      btrfs_file_extent_num_bytes(leaf, fi);
                                WARN_ON(!IS_ALIGNED(key.offset,
@@@ -1750,7 -1749,7 +1750,7 @@@ again
  
                btrfs_node_key_to_cpu(path->nodes[level], &key,
                                      path->slots[level]);
 -              btrfs_release_path(src, path);
 +              btrfs_release_path(path);
  
                path->lowest_level = level;
                ret = btrfs_search_slot(trans, src, &key, path, 0, 1);
@@@ -1894,7 -1893,6 +1894,7 @@@ static int invalidate_extent_cache(stru
        struct inode *inode = NULL;
        u64 objectid;
        u64 start, end;
 +      u64 ino;
  
        objectid = min_key->objectid;
        while (1) {
                inode = find_next_inode(root, objectid);
                if (!inode)
                        break;
 +              ino = btrfs_ino(inode);
  
 -              if (inode->i_ino > max_key->objectid) {
 +              if (ino > max_key->objectid) {
                        iput(inode);
                        break;
                }
  
 -              objectid = inode->i_ino + 1;
 +              objectid = ino + 1;
                if (!S_ISREG(inode->i_mode))
                        continue;
  
 -              if (unlikely(min_key->objectid == inode->i_ino)) {
 +              if (unlikely(min_key->objectid == ino)) {
                        if (min_key->type > BTRFS_EXTENT_DATA_KEY)
                                continue;
                        if (min_key->type < BTRFS_EXTENT_DATA_KEY)
                        start = 0;
                }
  
 -              if (unlikely(max_key->objectid == inode->i_ino)) {
 +              if (unlikely(max_key->objectid == ino)) {
                        if (max_key->type < BTRFS_EXTENT_DATA_KEY)
                                continue;
                        if (max_key->type > BTRFS_EXTENT_DATA_KEY) {
@@@ -2349,7 -2346,7 +2349,7 @@@ struct btrfs_root *select_one_root(stru
                root = next->root;
                BUG_ON(!root);
  
 -              /* no other choice for non-refernce counted tree */
 +              /* no other choice for non-references counted tree */
                if (!root->ref_cows)
                        return root;
  
@@@ -2499,7 -2496,7 +2499,7 @@@ static int do_relocation(struct btrfs_t
                        path->locks[upper->level] = 0;
  
                        slot = path->slots[upper->level];
 -                      btrfs_release_path(NULL, path);
 +                      btrfs_release_path(path);
                } else {
                        ret = btrfs_bin_search(upper->eb, key, upper->level,
                                               &slot);
@@@ -2740,7 -2737,7 +2740,7 @@@ static int relocate_tree_block(struct b
                } else {
                        path->lowest_level = node->level;
                        ret = btrfs_search_slot(trans, root, key, path, 0, 1);
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        if (ret > 0)
                                ret = 0;
                }
@@@ -2873,7 -2870,7 +2873,7 @@@ int setup_extent_mapping(struct inode *
        struct extent_map *em;
        int ret = 0;
  
 -      em = alloc_extent_map(GFP_NOFS);
 +      em = alloc_extent_map();
        if (!em)
                return -ENOMEM;
  
@@@ -3122,7 -3119,7 +3122,7 @@@ static int add_tree_block(struct reloc_
  #endif
        }
  
 -      btrfs_release_path(rc->extent_root, path);
 +      btrfs_release_path(path);
  
        BUG_ON(level == -1);
  
@@@ -3223,7 -3220,7 +3223,7 @@@ static int delete_block_group_cache(str
        key.offset = 0;
  
        inode = btrfs_iget(fs_info->sb, &key, root, NULL);
 -      if (!inode || IS_ERR(inode) || is_bad_inode(inode)) {
 +      if (IS_ERR_OR_NULL(inode) || is_bad_inode(inode)) {
                if (inode && !IS_ERR(inode))
                        iput(inode);
                return -ENOENT;
@@@ -3508,7 -3505,7 +3508,7 @@@ int add_data_references(struct reloc_co
                }
                path->slots[0]++;
        }
 -      btrfs_release_path(rc->extent_root, path);
 +      btrfs_release_path(path);
        if (err)
                free_block_list(blocks);
        return err;
@@@ -3571,7 -3568,7 +3571,7 @@@ next
                                            EXTENT_DIRTY);
  
                if (ret == 0 && start <= key.objectid) {
 -                      btrfs_release_path(rc->extent_root, path);
 +                      btrfs_release_path(path);
                        rc->search_start = end + 1;
                } else {
                        rc->search_start = key.objectid + key.offset;
                        return 0;
                }
        }
 -      btrfs_release_path(rc->extent_root, path);
 +      btrfs_release_path(path);
        return ret;
  }
  
@@@ -3716,7 -3713,7 +3716,7 @@@ restart
                                flags = BTRFS_EXTENT_FLAG_DATA;
  
                        if (path_change) {
 -                              btrfs_release_path(rc->extent_root, path);
 +                              btrfs_release_path(path);
  
                                path->search_commit_root = 1;
                                path->skip_locking = 1;
                           (flags & BTRFS_EXTENT_FLAG_DATA)) {
                        ret = add_data_references(rc, &key, path, &blocks);
                } else {
 -                      btrfs_release_path(rc->extent_root, path);
 +                      btrfs_release_path(path);
                        ret = 0;
                }
                if (ret < 0) {
                }
        }
  
 -      btrfs_release_path(rc->extent_root, path);
 +      btrfs_release_path(path);
        clear_extent_bits(&rc->processed_blocks, 0, (u64)-1, EXTENT_DIRTY,
                          GFP_NOFS);
  
@@@ -3870,7 -3867,7 +3870,7 @@@ static int __insert_orphan_inode(struc
        btrfs_set_inode_flags(leaf, item, BTRFS_INODE_NOCOMPRESS |
                                          BTRFS_INODE_PREALLOC);
        btrfs_mark_buffer_dirty(leaf);
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
  out:
        btrfs_free_path(path);
        return ret;
@@@ -3900,7 -3897,7 +3900,7 @@@ struct inode *create_reloc_inode(struc
        if (IS_ERR(trans))
                return ERR_CAST(trans);
  
 -      err = btrfs_find_free_objectid(trans, root, objectid, &objectid);
 +      err = btrfs_find_free_objectid(root, &objectid);
        if (err)
                goto out;
  
@@@ -3938,7 -3935,7 +3938,7 @@@ static struct reloc_control *alloc_relo
        INIT_LIST_HEAD(&rc->reloc_roots);
        backref_cache_init(&rc->backref_cache);
        mapping_tree_init(&rc->reloc_root_tree);
 -      extent_io_tree_init(&rc->processed_blocks, NULL, GFP_NOFS);
 +      extent_io_tree_init(&rc->processed_blocks, NULL);
        return rc;
  }
  
@@@ -4112,7 -4109,7 +4112,7 @@@ int btrfs_recover_relocation(struct btr
                }
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 -              btrfs_release_path(root->fs_info->tree_root, path);
 +              btrfs_release_path(path);
  
                if (key.objectid != BTRFS_TREE_RELOC_OBJECTID ||
                    key.type != BTRFS_ROOT_ITEM_KEY)
  
                key.offset--;
        }
 -      btrfs_release_path(root->fs_info->tree_root, path);
 +      btrfs_release_path(path);
  
        if (list_empty(&reloc_roots))
                goto out;
@@@ -4245,7 -4242,7 +4245,7 @@@ int btrfs_reloc_clone_csums(struct inod
  
        disk_bytenr = file_pos + BTRFS_I(inode)->index_cnt;
        ret = btrfs_lookup_csums_range(root->fs_info->csum_root, disk_bytenr,
-                                      disk_bytenr + len - 1, &list);
+                                      disk_bytenr + len - 1, &list, 0);
  
        while (!list_empty(&list)) {
                sums = list_entry(list.next, struct btrfs_ordered_sum, list);
diff --combined fs/btrfs/scrub.c
index 0000000,a31f2a9..87a2f12
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1368 +1,1368 @@@
 -      rw |= REQ_SYNC | REQ_UNPLUG;
+ /*
+  * Copyright (C) 2011 STRATO.  All rights reserved.
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public
+  * License v2 as published by the Free Software Foundation.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public
+  * License along with this program; if not, write to the
+  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  * Boston, MA 021110-1307, USA.
+  */
+ #include <linux/sched.h>
+ #include <linux/pagemap.h>
+ #include <linux/writeback.h>
+ #include <linux/blkdev.h>
+ #include <linux/rbtree.h>
+ #include <linux/slab.h>
+ #include <linux/workqueue.h>
+ #include "ctree.h"
+ #include "volumes.h"
+ #include "disk-io.h"
+ #include "ordered-data.h"
+ /*
+  * This is only the first step towards a full-features scrub. It reads all
+  * extent and super block and verifies the checksums. In case a bad checksum
+  * is found or the extent cannot be read, good data will be written back if
+  * any can be found.
+  *
+  * Future enhancements:
+  *  - To enhance the performance, better read-ahead strategies for the
+  *    extent-tree can be employed.
+  *  - In case an unrepairable extent is encountered, track which files are
+  *    affected and report them
+  *  - In case of a read error on files with nodatasum, map the file and read
+  *    the extent to trigger a writeback of the good copy
+  *  - track and record media errors, throw out bad devices
+  *  - add a mode to also read unallocated space
+  *  - make the prefetch cancellable
+  */
+ struct scrub_bio;
+ struct scrub_page;
+ struct scrub_dev;
+ static void scrub_bio_end_io(struct bio *bio, int err);
+ static void scrub_checksum(struct btrfs_work *work);
+ static int scrub_checksum_data(struct scrub_dev *sdev,
+                              struct scrub_page *spag, void *buffer);
+ static int scrub_checksum_tree_block(struct scrub_dev *sdev,
+                                    struct scrub_page *spag, u64 logical,
+                                    void *buffer);
+ static int scrub_checksum_super(struct scrub_bio *sbio, void *buffer);
+ static int scrub_fixup_check(struct scrub_bio *sbio, int ix);
+ static void scrub_fixup_end_io(struct bio *bio, int err);
+ static int scrub_fixup_io(int rw, struct block_device *bdev, sector_t sector,
+                         struct page *page);
+ static void scrub_fixup(struct scrub_bio *sbio, int ix);
+ #define SCRUB_PAGES_PER_BIO   16      /* 64k per bio */
+ #define SCRUB_BIOS_PER_DEV    16      /* 1 MB per device in flight */
+ struct scrub_page {
+       u64                     flags;  /* extent flags */
+       u64                     generation;
+       u64                     mirror_num;
+       int                     have_csum;
+       u8                      csum[BTRFS_CSUM_SIZE];
+ };
+ struct scrub_bio {
+       int                     index;
+       struct scrub_dev        *sdev;
+       struct bio              *bio;
+       int                     err;
+       u64                     logical;
+       u64                     physical;
+       struct scrub_page       spag[SCRUB_PAGES_PER_BIO];
+       u64                     count;
+       int                     next_free;
+       struct btrfs_work       work;
+ };
+ struct scrub_dev {
+       struct scrub_bio        *bios[SCRUB_BIOS_PER_DEV];
+       struct btrfs_device     *dev;
+       int                     first_free;
+       int                     curr;
+       atomic_t                in_flight;
+       spinlock_t              list_lock;
+       wait_queue_head_t       list_wait;
+       u16                     csum_size;
+       struct list_head        csum_list;
+       atomic_t                cancel_req;
+       int                     readonly;
+       /*
+        * statistics
+        */
+       struct btrfs_scrub_progress stat;
+       spinlock_t              stat_lock;
+ };
+ static void scrub_free_csums(struct scrub_dev *sdev)
+ {
+       while (!list_empty(&sdev->csum_list)) {
+               struct btrfs_ordered_sum *sum;
+               sum = list_first_entry(&sdev->csum_list,
+                                      struct btrfs_ordered_sum, list);
+               list_del(&sum->list);
+               kfree(sum);
+       }
+ }
+ static noinline_for_stack void scrub_free_dev(struct scrub_dev *sdev)
+ {
+       int i;
+       int j;
+       struct page *last_page;
+       if (!sdev)
+               return;
+       for (i = 0; i < SCRUB_BIOS_PER_DEV; ++i) {
+               struct scrub_bio *sbio = sdev->bios[i];
+               struct bio *bio;
+               if (!sbio)
+                       break;
+               bio = sbio->bio;
+               if (bio) {
+                       last_page = NULL;
+                       for (j = 0; j < bio->bi_vcnt; ++j) {
+                               if (bio->bi_io_vec[j].bv_page == last_page)
+                                       continue;
+                               last_page = bio->bi_io_vec[j].bv_page;
+                               __free_page(last_page);
+                       }
+                       bio_put(bio);
+               }
+               kfree(sbio);
+       }
+       scrub_free_csums(sdev);
+       kfree(sdev);
+ }
+ static noinline_for_stack
+ struct scrub_dev *scrub_setup_dev(struct btrfs_device *dev)
+ {
+       struct scrub_dev *sdev;
+       int             i;
+       int             j;
+       int             ret;
+       struct btrfs_fs_info *fs_info = dev->dev_root->fs_info;
+       sdev = kzalloc(sizeof(*sdev), GFP_NOFS);
+       if (!sdev)
+               goto nomem;
+       sdev->dev = dev;
+       for (i = 0; i < SCRUB_BIOS_PER_DEV; ++i) {
+               struct bio *bio;
+               struct scrub_bio *sbio;
+               sbio = kzalloc(sizeof(*sbio), GFP_NOFS);
+               if (!sbio)
+                       goto nomem;
+               sdev->bios[i] = sbio;
+               bio = bio_kmalloc(GFP_NOFS, SCRUB_PAGES_PER_BIO);
+               if (!bio)
+                       goto nomem;
+               sbio->index = i;
+               sbio->sdev = sdev;
+               sbio->bio = bio;
+               sbio->count = 0;
+               sbio->work.func = scrub_checksum;
+               bio->bi_private = sdev->bios[i];
+               bio->bi_end_io = scrub_bio_end_io;
+               bio->bi_sector = 0;
+               bio->bi_bdev = dev->bdev;
+               bio->bi_size = 0;
+               for (j = 0; j < SCRUB_PAGES_PER_BIO; ++j) {
+                       struct page *page;
+                       page = alloc_page(GFP_NOFS);
+                       if (!page)
+                               goto nomem;
+                       ret = bio_add_page(bio, page, PAGE_SIZE, 0);
+                       if (!ret)
+                               goto nomem;
+               }
+               WARN_ON(bio->bi_vcnt != SCRUB_PAGES_PER_BIO);
+               if (i != SCRUB_BIOS_PER_DEV-1)
+                       sdev->bios[i]->next_free = i + 1;
+                else
+                       sdev->bios[i]->next_free = -1;
+       }
+       sdev->first_free = 0;
+       sdev->curr = -1;
+       atomic_set(&sdev->in_flight, 0);
+       atomic_set(&sdev->cancel_req, 0);
+       sdev->csum_size = btrfs_super_csum_size(&fs_info->super_copy);
+       INIT_LIST_HEAD(&sdev->csum_list);
+       spin_lock_init(&sdev->list_lock);
+       spin_lock_init(&sdev->stat_lock);
+       init_waitqueue_head(&sdev->list_wait);
+       return sdev;
+ nomem:
+       scrub_free_dev(sdev);
+       return ERR_PTR(-ENOMEM);
+ }
+ /*
+  * scrub_recheck_error gets called when either verification of the page
+  * failed or the bio failed to read, e.g. with EIO. In the latter case,
+  * recheck_error gets called for every page in the bio, even though only
+  * one may be bad
+  */
+ static void scrub_recheck_error(struct scrub_bio *sbio, int ix)
+ {
+       if (sbio->err) {
+               if (scrub_fixup_io(READ, sbio->sdev->dev->bdev,
+                                  (sbio->physical + ix * PAGE_SIZE) >> 9,
+                                  sbio->bio->bi_io_vec[ix].bv_page) == 0) {
+                       if (scrub_fixup_check(sbio, ix) == 0)
+                               return;
+               }
+       }
+       scrub_fixup(sbio, ix);
+ }
+ static int scrub_fixup_check(struct scrub_bio *sbio, int ix)
+ {
+       int ret = 1;
+       struct page *page;
+       void *buffer;
+       u64 flags = sbio->spag[ix].flags;
+       page = sbio->bio->bi_io_vec[ix].bv_page;
+       buffer = kmap_atomic(page, KM_USER0);
+       if (flags & BTRFS_EXTENT_FLAG_DATA) {
+               ret = scrub_checksum_data(sbio->sdev,
+                                         sbio->spag + ix, buffer);
+       } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
+               ret = scrub_checksum_tree_block(sbio->sdev,
+                                               sbio->spag + ix,
+                                               sbio->logical + ix * PAGE_SIZE,
+                                               buffer);
+       } else {
+               WARN_ON(1);
+       }
+       kunmap_atomic(buffer, KM_USER0);
+       return ret;
+ }
+ static void scrub_fixup_end_io(struct bio *bio, int err)
+ {
+       complete((struct completion *)bio->bi_private);
+ }
+ static void scrub_fixup(struct scrub_bio *sbio, int ix)
+ {
+       struct scrub_dev *sdev = sbio->sdev;
+       struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info;
+       struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
+       struct btrfs_multi_bio *multi = NULL;
+       u64 logical = sbio->logical + ix * PAGE_SIZE;
+       u64 length;
+       int i;
+       int ret;
+       DECLARE_COMPLETION_ONSTACK(complete);
+       if ((sbio->spag[ix].flags & BTRFS_EXTENT_FLAG_DATA) &&
+           (sbio->spag[ix].have_csum == 0)) {
+               /*
+                * nodatasum, don't try to fix anything
+                * FIXME: we can do better, open the inode and trigger a
+                * writeback
+                */
+               goto uncorrectable;
+       }
+       length = PAGE_SIZE;
+       ret = btrfs_map_block(map_tree, REQ_WRITE, logical, &length,
+                             &multi, 0);
+       if (ret || !multi || length < PAGE_SIZE) {
+               printk(KERN_ERR
+                      "scrub_fixup: btrfs_map_block failed us for %llu\n",
+                      (unsigned long long)logical);
+               WARN_ON(1);
+               return;
+       }
+       if (multi->num_stripes == 1)
+               /* there aren't any replicas */
+               goto uncorrectable;
+       /*
+        * first find a good copy
+        */
+       for (i = 0; i < multi->num_stripes; ++i) {
+               if (i == sbio->spag[ix].mirror_num)
+                       continue;
+               if (scrub_fixup_io(READ, multi->stripes[i].dev->bdev,
+                                  multi->stripes[i].physical >> 9,
+                                  sbio->bio->bi_io_vec[ix].bv_page)) {
+                       /* I/O-error, this is not a good copy */
+                       continue;
+               }
+               if (scrub_fixup_check(sbio, ix) == 0)
+                       break;
+       }
+       if (i == multi->num_stripes)
+               goto uncorrectable;
+       if (!sdev->readonly) {
+               /*
+                * bi_io_vec[ix].bv_page now contains good data, write it back
+                */
+               if (scrub_fixup_io(WRITE, sdev->dev->bdev,
+                                  (sbio->physical + ix * PAGE_SIZE) >> 9,
+                                  sbio->bio->bi_io_vec[ix].bv_page)) {
+                       /* I/O-error, writeback failed, give up */
+                       goto uncorrectable;
+               }
+       }
+       kfree(multi);
+       spin_lock(&sdev->stat_lock);
+       ++sdev->stat.corrected_errors;
+       spin_unlock(&sdev->stat_lock);
+       if (printk_ratelimit())
+               printk(KERN_ERR "btrfs: fixed up at %llu\n",
+                      (unsigned long long)logical);
+       return;
+ uncorrectable:
+       kfree(multi);
+       spin_lock(&sdev->stat_lock);
+       ++sdev->stat.uncorrectable_errors;
+       spin_unlock(&sdev->stat_lock);
+       if (printk_ratelimit())
+               printk(KERN_ERR "btrfs: unable to fixup at %llu\n",
+                        (unsigned long long)logical);
+ }
+ static int scrub_fixup_io(int rw, struct block_device *bdev, sector_t sector,
+                        struct page *page)
+ {
+       struct bio *bio = NULL;
+       int ret;
+       DECLARE_COMPLETION_ONSTACK(complete);
+       /* we are going to wait on this IO */
 -              btrfs_release_path(root, path);
++      rw |= REQ_SYNC;
+       bio = bio_alloc(GFP_NOFS, 1);
+       bio->bi_bdev = bdev;
+       bio->bi_sector = sector;
+       bio_add_page(bio, page, PAGE_SIZE, 0);
+       bio->bi_end_io = scrub_fixup_end_io;
+       bio->bi_private = &complete;
+       submit_bio(rw, bio);
+       wait_for_completion(&complete);
+       ret = !test_bit(BIO_UPTODATE, &bio->bi_flags);
+       bio_put(bio);
+       return ret;
+ }
+ static void scrub_bio_end_io(struct bio *bio, int err)
+ {
+       struct scrub_bio *sbio = bio->bi_private;
+       struct scrub_dev *sdev = sbio->sdev;
+       struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info;
+       sbio->err = err;
+       btrfs_queue_worker(&fs_info->scrub_workers, &sbio->work);
+ }
+ static void scrub_checksum(struct btrfs_work *work)
+ {
+       struct scrub_bio *sbio = container_of(work, struct scrub_bio, work);
+       struct scrub_dev *sdev = sbio->sdev;
+       struct page *page;
+       void *buffer;
+       int i;
+       u64 flags;
+       u64 logical;
+       int ret;
+       if (sbio->err) {
+               for (i = 0; i < sbio->count; ++i)
+                       scrub_recheck_error(sbio, i);
+               sbio->bio->bi_flags &= ~(BIO_POOL_MASK - 1);
+               sbio->bio->bi_flags |= 1 << BIO_UPTODATE;
+               sbio->bio->bi_phys_segments = 0;
+               sbio->bio->bi_idx = 0;
+               for (i = 0; i < sbio->count; i++) {
+                       struct bio_vec *bi;
+                       bi = &sbio->bio->bi_io_vec[i];
+                       bi->bv_offset = 0;
+                       bi->bv_len = PAGE_SIZE;
+               }
+               spin_lock(&sdev->stat_lock);
+               ++sdev->stat.read_errors;
+               spin_unlock(&sdev->stat_lock);
+               goto out;
+       }
+       for (i = 0; i < sbio->count; ++i) {
+               page = sbio->bio->bi_io_vec[i].bv_page;
+               buffer = kmap_atomic(page, KM_USER0);
+               flags = sbio->spag[i].flags;
+               logical = sbio->logical + i * PAGE_SIZE;
+               ret = 0;
+               if (flags & BTRFS_EXTENT_FLAG_DATA) {
+                       ret = scrub_checksum_data(sdev, sbio->spag + i, buffer);
+               } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
+                       ret = scrub_checksum_tree_block(sdev, sbio->spag + i,
+                                                       logical, buffer);
+               } else if (flags & BTRFS_EXTENT_FLAG_SUPER) {
+                       BUG_ON(i);
+                       (void)scrub_checksum_super(sbio, buffer);
+               } else {
+                       WARN_ON(1);
+               }
+               kunmap_atomic(buffer, KM_USER0);
+               if (ret)
+                       scrub_recheck_error(sbio, i);
+       }
+ out:
+       spin_lock(&sdev->list_lock);
+       sbio->next_free = sdev->first_free;
+       sdev->first_free = sbio->index;
+       spin_unlock(&sdev->list_lock);
+       atomic_dec(&sdev->in_flight);
+       wake_up(&sdev->list_wait);
+ }
+ static int scrub_checksum_data(struct scrub_dev *sdev,
+                              struct scrub_page *spag, void *buffer)
+ {
+       u8 csum[BTRFS_CSUM_SIZE];
+       u32 crc = ~(u32)0;
+       int fail = 0;
+       struct btrfs_root *root = sdev->dev->dev_root;
+       if (!spag->have_csum)
+               return 0;
+       crc = btrfs_csum_data(root, buffer, crc, PAGE_SIZE);
+       btrfs_csum_final(crc, csum);
+       if (memcmp(csum, spag->csum, sdev->csum_size))
+               fail = 1;
+       spin_lock(&sdev->stat_lock);
+       ++sdev->stat.data_extents_scrubbed;
+       sdev->stat.data_bytes_scrubbed += PAGE_SIZE;
+       if (fail)
+               ++sdev->stat.csum_errors;
+       spin_unlock(&sdev->stat_lock);
+       return fail;
+ }
+ static int scrub_checksum_tree_block(struct scrub_dev *sdev,
+                                    struct scrub_page *spag, u64 logical,
+                                    void *buffer)
+ {
+       struct btrfs_header *h;
+       struct btrfs_root *root = sdev->dev->dev_root;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       u8 csum[BTRFS_CSUM_SIZE];
+       u32 crc = ~(u32)0;
+       int fail = 0;
+       int crc_fail = 0;
+       /*
+        * we don't use the getter functions here, as we
+        * a) don't have an extent buffer and
+        * b) the page is already kmapped
+        */
+       h = (struct btrfs_header *)buffer;
+       if (logical != le64_to_cpu(h->bytenr))
+               ++fail;
+       if (spag->generation != le64_to_cpu(h->generation))
+               ++fail;
+       if (memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
+               ++fail;
+       if (memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
+                  BTRFS_UUID_SIZE))
+               ++fail;
+       crc = btrfs_csum_data(root, buffer + BTRFS_CSUM_SIZE, crc,
+                             PAGE_SIZE - BTRFS_CSUM_SIZE);
+       btrfs_csum_final(crc, csum);
+       if (memcmp(csum, h->csum, sdev->csum_size))
+               ++crc_fail;
+       spin_lock(&sdev->stat_lock);
+       ++sdev->stat.tree_extents_scrubbed;
+       sdev->stat.tree_bytes_scrubbed += PAGE_SIZE;
+       if (crc_fail)
+               ++sdev->stat.csum_errors;
+       if (fail)
+               ++sdev->stat.verify_errors;
+       spin_unlock(&sdev->stat_lock);
+       return fail || crc_fail;
+ }
+ static int scrub_checksum_super(struct scrub_bio *sbio, void *buffer)
+ {
+       struct btrfs_super_block *s;
+       u64 logical;
+       struct scrub_dev *sdev = sbio->sdev;
+       struct btrfs_root *root = sdev->dev->dev_root;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       u8 csum[BTRFS_CSUM_SIZE];
+       u32 crc = ~(u32)0;
+       int fail = 0;
+       s = (struct btrfs_super_block *)buffer;
+       logical = sbio->logical;
+       if (logical != le64_to_cpu(s->bytenr))
+               ++fail;
+       if (sbio->spag[0].generation != le64_to_cpu(s->generation))
+               ++fail;
+       if (memcmp(s->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
+               ++fail;
+       crc = btrfs_csum_data(root, buffer + BTRFS_CSUM_SIZE, crc,
+                             PAGE_SIZE - BTRFS_CSUM_SIZE);
+       btrfs_csum_final(crc, csum);
+       if (memcmp(csum, s->csum, sbio->sdev->csum_size))
+               ++fail;
+       if (fail) {
+               /*
+                * if we find an error in a super block, we just report it.
+                * They will get written with the next transaction commit
+                * anyway
+                */
+               spin_lock(&sdev->stat_lock);
+               ++sdev->stat.super_errors;
+               spin_unlock(&sdev->stat_lock);
+       }
+       return fail;
+ }
+ static int scrub_submit(struct scrub_dev *sdev)
+ {
+       struct scrub_bio *sbio;
+       if (sdev->curr == -1)
+               return 0;
+       sbio = sdev->bios[sdev->curr];
+       sbio->bio->bi_sector = sbio->physical >> 9;
+       sbio->bio->bi_size = sbio->count * PAGE_SIZE;
+       sbio->bio->bi_next = NULL;
+       sbio->bio->bi_flags |= 1 << BIO_UPTODATE;
+       sbio->bio->bi_comp_cpu = -1;
+       sbio->bio->bi_bdev = sdev->dev->bdev;
+       sbio->err = 0;
+       sdev->curr = -1;
+       atomic_inc(&sdev->in_flight);
+       submit_bio(0, sbio->bio);
+       return 0;
+ }
+ static int scrub_page(struct scrub_dev *sdev, u64 logical, u64 len,
+                     u64 physical, u64 flags, u64 gen, u64 mirror_num,
+                     u8 *csum, int force)
+ {
+       struct scrub_bio *sbio;
+ again:
+       /*
+        * grab a fresh bio or wait for one to become available
+        */
+       while (sdev->curr == -1) {
+               spin_lock(&sdev->list_lock);
+               sdev->curr = sdev->first_free;
+               if (sdev->curr != -1) {
+                       sdev->first_free = sdev->bios[sdev->curr]->next_free;
+                       sdev->bios[sdev->curr]->next_free = -1;
+                       sdev->bios[sdev->curr]->count = 0;
+                       spin_unlock(&sdev->list_lock);
+               } else {
+                       spin_unlock(&sdev->list_lock);
+                       wait_event(sdev->list_wait, sdev->first_free != -1);
+               }
+       }
+       sbio = sdev->bios[sdev->curr];
+       if (sbio->count == 0) {
+               sbio->physical = physical;
+               sbio->logical = logical;
+       } else if (sbio->physical + sbio->count * PAGE_SIZE != physical) {
+               scrub_submit(sdev);
+               goto again;
+       }
+       sbio->spag[sbio->count].flags = flags;
+       sbio->spag[sbio->count].generation = gen;
+       sbio->spag[sbio->count].have_csum = 0;
+       sbio->spag[sbio->count].mirror_num = mirror_num;
+       if (csum) {
+               sbio->spag[sbio->count].have_csum = 1;
+               memcpy(sbio->spag[sbio->count].csum, csum, sdev->csum_size);
+       }
+       ++sbio->count;
+       if (sbio->count == SCRUB_PAGES_PER_BIO || force)
+               scrub_submit(sdev);
+       return 0;
+ }
+ static int scrub_find_csum(struct scrub_dev *sdev, u64 logical, u64 len,
+                          u8 *csum)
+ {
+       struct btrfs_ordered_sum *sum = NULL;
+       int ret = 0;
+       unsigned long i;
+       unsigned long num_sectors;
+       u32 sectorsize = sdev->dev->dev_root->sectorsize;
+       while (!list_empty(&sdev->csum_list)) {
+               sum = list_first_entry(&sdev->csum_list,
+                                      struct btrfs_ordered_sum, list);
+               if (sum->bytenr > logical)
+                       return 0;
+               if (sum->bytenr + sum->len > logical)
+                       break;
+               ++sdev->stat.csum_discards;
+               list_del(&sum->list);
+               kfree(sum);
+               sum = NULL;
+       }
+       if (!sum)
+               return 0;
+       num_sectors = sum->len / sectorsize;
+       for (i = 0; i < num_sectors; ++i) {
+               if (sum->sums[i].bytenr == logical) {
+                       memcpy(csum, &sum->sums[i].sum, sdev->csum_size);
+                       ret = 1;
+                       break;
+               }
+       }
+       if (ret && i == num_sectors - 1) {
+               list_del(&sum->list);
+               kfree(sum);
+       }
+       return ret;
+ }
+ /* scrub extent tries to collect up to 64 kB for each bio */
+ static int scrub_extent(struct scrub_dev *sdev, u64 logical, u64 len,
+                       u64 physical, u64 flags, u64 gen, u64 mirror_num)
+ {
+       int ret;
+       u8 csum[BTRFS_CSUM_SIZE];
+       while (len) {
+               u64 l = min_t(u64, len, PAGE_SIZE);
+               int have_csum = 0;
+               if (flags & BTRFS_EXTENT_FLAG_DATA) {
+                       /* push csums to sbio */
+                       have_csum = scrub_find_csum(sdev, logical, l, csum);
+                       if (have_csum == 0)
+                               ++sdev->stat.no_csum;
+               }
+               ret = scrub_page(sdev, logical, l, physical, flags, gen,
+                                mirror_num, have_csum ? csum : NULL, 0);
+               if (ret)
+                       return ret;
+               len -= l;
+               logical += l;
+               physical += l;
+       }
+       return 0;
+ }
+ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev,
+       struct map_lookup *map, int num, u64 base, u64 length)
+ {
+       struct btrfs_path *path;
+       struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info;
+       struct btrfs_root *root = fs_info->extent_root;
+       struct btrfs_root *csum_root = fs_info->csum_root;
+       struct btrfs_extent_item *extent;
+       u64 flags;
+       int ret;
+       int slot;
+       int i;
+       u64 nstripes;
+       int start_stripe;
+       struct extent_buffer *l;
+       struct btrfs_key key;
+       u64 physical;
+       u64 logical;
+       u64 generation;
+       u64 mirror_num;
+       u64 increment = map->stripe_len;
+       u64 offset;
+       nstripes = length;
+       offset = 0;
+       do_div(nstripes, map->stripe_len);
+       if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
+               offset = map->stripe_len * num;
+               increment = map->stripe_len * map->num_stripes;
+               mirror_num = 0;
+       } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
+               int factor = map->num_stripes / map->sub_stripes;
+               offset = map->stripe_len * (num / map->sub_stripes);
+               increment = map->stripe_len * factor;
+               mirror_num = num % map->sub_stripes;
+       } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
+               increment = map->stripe_len;
+               mirror_num = num % map->num_stripes;
+       } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
+               increment = map->stripe_len;
+               mirror_num = num % map->num_stripes;
+       } else {
+               increment = map->stripe_len;
+               mirror_num = 0;
+       }
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+       path->reada = 2;
+       path->search_commit_root = 1;
+       path->skip_locking = 1;
+       /*
+        * find all extents for each stripe and just read them to get
+        * them into the page cache
+        * FIXME: we can do better. build a more intelligent prefetching
+        */
+       logical = base + offset;
+       physical = map->stripes[num].physical;
+       ret = 0;
+       for (i = 0; i < nstripes; ++i) {
+               key.objectid = logical;
+               key.type = BTRFS_EXTENT_ITEM_KEY;
+               key.offset = (u64)0;
+               ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+               if (ret < 0)
+                       goto out;
+               l = path->nodes[0];
+               slot = path->slots[0];
+               btrfs_item_key_to_cpu(l, &key, slot);
+               if (key.objectid != logical) {
+                       ret = btrfs_previous_item(root, path, 0,
+                                                 BTRFS_EXTENT_ITEM_KEY);
+                       if (ret < 0)
+                               goto out;
+               }
+               while (1) {
+                       l = path->nodes[0];
+                       slot = path->slots[0];
+                       if (slot >= btrfs_header_nritems(l)) {
+                               ret = btrfs_next_leaf(root, path);
+                               if (ret == 0)
+                                       continue;
+                               if (ret < 0)
+                                       goto out;
+                               break;
+                       }
+                       btrfs_item_key_to_cpu(l, &key, slot);
+                       if (key.objectid >= logical + map->stripe_len)
+                               break;
+                       path->slots[0]++;
+               }
 -              btrfs_release_path(root, path);
++              btrfs_release_path(path);
+               logical += increment;
+               physical += map->stripe_len;
+               cond_resched();
+       }
+       /*
+        * collect all data csums for the stripe to avoid seeking during
+        * the scrub. This might currently (crc32) end up to be about 1MB
+        */
+       start_stripe = 0;
+ again:
+       logical = base + offset + start_stripe * increment;
+       for (i = start_stripe; i < nstripes; ++i) {
+               ret = btrfs_lookup_csums_range(csum_root, logical,
+                                              logical + map->stripe_len - 1,
+                                              &sdev->csum_list, 1);
+               if (ret)
+                       goto out;
+               logical += increment;
+               cond_resched();
+       }
+       /*
+        * now find all extents for each stripe and scrub them
+        */
+       logical = base + offset + start_stripe * increment;
+       physical = map->stripes[num].physical + start_stripe * map->stripe_len;
+       ret = 0;
+       for (i = start_stripe; i < nstripes; ++i) {
+               /*
+                * canceled?
+                */
+               if (atomic_read(&fs_info->scrub_cancel_req) ||
+                   atomic_read(&sdev->cancel_req)) {
+                       ret = -ECANCELED;
+                       goto out;
+               }
+               /*
+                * check to see if we have to pause
+                */
+               if (atomic_read(&fs_info->scrub_pause_req)) {
+                       /* push queued extents */
+                       scrub_submit(sdev);
+                       wait_event(sdev->list_wait,
+                                  atomic_read(&sdev->in_flight) == 0);
+                       atomic_inc(&fs_info->scrubs_paused);
+                       wake_up(&fs_info->scrub_pause_wait);
+                       mutex_lock(&fs_info->scrub_lock);
+                       while (atomic_read(&fs_info->scrub_pause_req)) {
+                               mutex_unlock(&fs_info->scrub_lock);
+                               wait_event(fs_info->scrub_pause_wait,
+                                  atomic_read(&fs_info->scrub_pause_req) == 0);
+                               mutex_lock(&fs_info->scrub_lock);
+                       }
+                       atomic_dec(&fs_info->scrubs_paused);
+                       mutex_unlock(&fs_info->scrub_lock);
+                       wake_up(&fs_info->scrub_pause_wait);
+                       scrub_free_csums(sdev);
+                       start_stripe = i;
+                       goto again;
+               }
+               key.objectid = logical;
+               key.type = BTRFS_EXTENT_ITEM_KEY;
+               key.offset = (u64)0;
+               ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+               if (ret < 0)
+                       goto out;
+               l = path->nodes[0];
+               slot = path->slots[0];
+               btrfs_item_key_to_cpu(l, &key, slot);
+               if (key.objectid != logical) {
+                       ret = btrfs_previous_item(root, path, 0,
+                                                 BTRFS_EXTENT_ITEM_KEY);
+                       if (ret < 0)
+                               goto out;
+               }
+               while (1) {
+                       l = path->nodes[0];
+                       slot = path->slots[0];
+                       if (slot >= btrfs_header_nritems(l)) {
+                               ret = btrfs_next_leaf(root, path);
+                               if (ret == 0)
+                                       continue;
+                               if (ret < 0)
+                                       goto out;
+                               break;
+                       }
+                       btrfs_item_key_to_cpu(l, &key, slot);
+                       if (key.objectid + key.offset <= logical)
+                               goto next;
+                       if (key.objectid >= logical + map->stripe_len)
+                               break;
+                       if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY)
+                               goto next;
+                       extent = btrfs_item_ptr(l, slot,
+                                               struct btrfs_extent_item);
+                       flags = btrfs_extent_flags(l, extent);
+                       generation = btrfs_extent_generation(l, extent);
+                       if (key.objectid < logical &&
+                           (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)) {
+                               printk(KERN_ERR
+                                      "btrfs scrub: tree block %llu spanning "
+                                      "stripes, ignored. logical=%llu\n",
+                                      (unsigned long long)key.objectid,
+                                      (unsigned long long)logical);
+                               goto next;
+                       }
+                       /*
+                        * trim extent to this stripe
+                        */
+                       if (key.objectid < logical) {
+                               key.offset -= logical - key.objectid;
+                               key.objectid = logical;
+                       }
+                       if (key.objectid + key.offset >
+                           logical + map->stripe_len) {
+                               key.offset = logical + map->stripe_len -
+                                            key.objectid;
+                       }
+                       ret = scrub_extent(sdev, key.objectid, key.offset,
+                                          key.objectid - logical + physical,
+                                          flags, generation, mirror_num);
+                       if (ret)
+                               goto out;
+ next:
+                       path->slots[0]++;
+               }
 -                      btrfs_release_path(root, path);
++              btrfs_release_path(path);
+               logical += increment;
+               physical += map->stripe_len;
+               spin_lock(&sdev->stat_lock);
+               sdev->stat.last_physical = physical;
+               spin_unlock(&sdev->stat_lock);
+       }
+       /* push queued extents */
+       scrub_submit(sdev);
+ out:
+       btrfs_free_path(path);
+       return ret < 0 ? ret : 0;
+ }
+ static noinline_for_stack int scrub_chunk(struct scrub_dev *sdev,
+       u64 chunk_tree, u64 chunk_objectid, u64 chunk_offset, u64 length)
+ {
+       struct btrfs_mapping_tree *map_tree =
+               &sdev->dev->dev_root->fs_info->mapping_tree;
+       struct map_lookup *map;
+       struct extent_map *em;
+       int i;
+       int ret = -EINVAL;
+       read_lock(&map_tree->map_tree.lock);
+       em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1);
+       read_unlock(&map_tree->map_tree.lock);
+       if (!em)
+               return -EINVAL;
+       map = (struct map_lookup *)em->bdev;
+       if (em->start != chunk_offset)
+               goto out;
+       if (em->len < length)
+               goto out;
+       for (i = 0; i < map->num_stripes; ++i) {
+               if (map->stripes[i].dev == sdev->dev) {
+                       ret = scrub_stripe(sdev, map, i, chunk_offset, length);
+                       if (ret)
+                               goto out;
+               }
+       }
+ out:
+       free_extent_map(em);
+       return ret;
+ }
+ static noinline_for_stack
+ int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end)
+ {
+       struct btrfs_dev_extent *dev_extent = NULL;
+       struct btrfs_path *path;
+       struct btrfs_root *root = sdev->dev->dev_root;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       u64 length;
+       u64 chunk_tree;
+       u64 chunk_objectid;
+       u64 chunk_offset;
+       int ret;
+       int slot;
+       struct extent_buffer *l;
+       struct btrfs_key key;
+       struct btrfs_key found_key;
+       struct btrfs_block_group_cache *cache;
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+       path->reada = 2;
+       path->search_commit_root = 1;
+       path->skip_locking = 1;
+       key.objectid = sdev->dev->devid;
+       key.offset = 0ull;
+       key.type = BTRFS_DEV_EXTENT_KEY;
+       while (1) {
+               ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+               if (ret < 0)
+                       goto out;
+               ret = 0;
+               l = path->nodes[0];
+               slot = path->slots[0];
+               btrfs_item_key_to_cpu(l, &found_key, slot);
+               if (found_key.objectid != sdev->dev->devid)
+                       break;
+               if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
+                       break;
+               if (found_key.offset >= end)
+                       break;
+               if (found_key.offset < key.offset)
+                       break;
+               dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
+               length = btrfs_dev_extent_length(l, dev_extent);
+               if (found_key.offset + length <= start) {
+                       key.offset = found_key.offset + length;
 -              btrfs_release_path(root, path);
++                      btrfs_release_path(path);
+                       continue;
+               }
+               chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent);
+               chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent);
+               chunk_offset = btrfs_dev_extent_chunk_offset(l, dev_extent);
+               /*
+                * get a reference on the corresponding block group to prevent
+                * the chunk from going away while we scrub it
+                */
+               cache = btrfs_lookup_block_group(fs_info, chunk_offset);
+               if (!cache) {
+                       ret = -ENOENT;
+                       goto out;
+               }
+               ret = scrub_chunk(sdev, chunk_tree, chunk_objectid,
+                                 chunk_offset, length);
+               btrfs_put_block_group(cache);
+               if (ret)
+                       break;
+               key.offset = found_key.offset + length;
++              btrfs_release_path(path);
+       }
+ out:
+       btrfs_free_path(path);
+       return ret;
+ }
+ static noinline_for_stack int scrub_supers(struct scrub_dev *sdev)
+ {
+       int     i;
+       u64     bytenr;
+       u64     gen;
+       int     ret;
+       struct btrfs_device *device = sdev->dev;
+       struct btrfs_root *root = device->dev_root;
+       gen = root->fs_info->last_trans_committed;
+       for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+               bytenr = btrfs_sb_offset(i);
+               if (bytenr + BTRFS_SUPER_INFO_SIZE >= device->total_bytes)
+                       break;
+               ret = scrub_page(sdev, bytenr, PAGE_SIZE, bytenr,
+                                BTRFS_EXTENT_FLAG_SUPER, gen, i, NULL, 1);
+               if (ret)
+                       return ret;
+       }
+       wait_event(sdev->list_wait, atomic_read(&sdev->in_flight) == 0);
+       return 0;
+ }
+ /*
+  * get a reference count on fs_info->scrub_workers. start worker if necessary
+  */
+ static noinline_for_stack int scrub_workers_get(struct btrfs_root *root)
+ {
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       mutex_lock(&fs_info->scrub_lock);
+       if (fs_info->scrub_workers_refcnt == 0)
+               btrfs_start_workers(&fs_info->scrub_workers, 1);
+       ++fs_info->scrub_workers_refcnt;
+       mutex_unlock(&fs_info->scrub_lock);
+       return 0;
+ }
+ static noinline_for_stack void scrub_workers_put(struct btrfs_root *root)
+ {
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       mutex_lock(&fs_info->scrub_lock);
+       if (--fs_info->scrub_workers_refcnt == 0)
+               btrfs_stop_workers(&fs_info->scrub_workers);
+       WARN_ON(fs_info->scrub_workers_refcnt < 0);
+       mutex_unlock(&fs_info->scrub_lock);
+ }
+ int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end,
+                   struct btrfs_scrub_progress *progress, int readonly)
+ {
+       struct scrub_dev *sdev;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       int ret;
+       struct btrfs_device *dev;
+       if (root->fs_info->closing)
+               return -EINVAL;
+       /*
+        * check some assumptions
+        */
+       if (root->sectorsize != PAGE_SIZE ||
+           root->sectorsize != root->leafsize ||
+           root->sectorsize != root->nodesize) {
+               printk(KERN_ERR "btrfs_scrub: size assumptions fail\n");
+               return -EINVAL;
+       }
+       ret = scrub_workers_get(root);
+       if (ret)
+               return ret;
+       mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+       dev = btrfs_find_device(root, devid, NULL, NULL);
+       if (!dev || dev->missing) {
+               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+               scrub_workers_put(root);
+               return -ENODEV;
+       }
+       mutex_lock(&fs_info->scrub_lock);
+       if (!dev->in_fs_metadata) {
+               mutex_unlock(&fs_info->scrub_lock);
+               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+               scrub_workers_put(root);
+               return -ENODEV;
+       }
+       if (dev->scrub_device) {
+               mutex_unlock(&fs_info->scrub_lock);
+               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+               scrub_workers_put(root);
+               return -EINPROGRESS;
+       }
+       sdev = scrub_setup_dev(dev);
+       if (IS_ERR(sdev)) {
+               mutex_unlock(&fs_info->scrub_lock);
+               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+               scrub_workers_put(root);
+               return PTR_ERR(sdev);
+       }
+       sdev->readonly = readonly;
+       dev->scrub_device = sdev;
+       atomic_inc(&fs_info->scrubs_running);
+       mutex_unlock(&fs_info->scrub_lock);
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+       down_read(&fs_info->scrub_super_lock);
+       ret = scrub_supers(sdev);
+       up_read(&fs_info->scrub_super_lock);
+       if (!ret)
+               ret = scrub_enumerate_chunks(sdev, start, end);
+       wait_event(sdev->list_wait, atomic_read(&sdev->in_flight) == 0);
+       atomic_dec(&fs_info->scrubs_running);
+       wake_up(&fs_info->scrub_pause_wait);
+       if (progress)
+               memcpy(progress, &sdev->stat, sizeof(*progress));
+       mutex_lock(&fs_info->scrub_lock);
+       dev->scrub_device = NULL;
+       mutex_unlock(&fs_info->scrub_lock);
+       scrub_free_dev(sdev);
+       scrub_workers_put(root);
+       return ret;
+ }
+ int btrfs_scrub_pause(struct btrfs_root *root)
+ {
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       mutex_lock(&fs_info->scrub_lock);
+       atomic_inc(&fs_info->scrub_pause_req);
+       while (atomic_read(&fs_info->scrubs_paused) !=
+              atomic_read(&fs_info->scrubs_running)) {
+               mutex_unlock(&fs_info->scrub_lock);
+               wait_event(fs_info->scrub_pause_wait,
+                          atomic_read(&fs_info->scrubs_paused) ==
+                          atomic_read(&fs_info->scrubs_running));
+               mutex_lock(&fs_info->scrub_lock);
+       }
+       mutex_unlock(&fs_info->scrub_lock);
+       return 0;
+ }
+ int btrfs_scrub_continue(struct btrfs_root *root)
+ {
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       atomic_dec(&fs_info->scrub_pause_req);
+       wake_up(&fs_info->scrub_pause_wait);
+       return 0;
+ }
+ int btrfs_scrub_pause_super(struct btrfs_root *root)
+ {
+       down_write(&root->fs_info->scrub_super_lock);
+       return 0;
+ }
+ int btrfs_scrub_continue_super(struct btrfs_root *root)
+ {
+       up_write(&root->fs_info->scrub_super_lock);
+       return 0;
+ }
+ int btrfs_scrub_cancel(struct btrfs_root *root)
+ {
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       mutex_lock(&fs_info->scrub_lock);
+       if (!atomic_read(&fs_info->scrubs_running)) {
+               mutex_unlock(&fs_info->scrub_lock);
+               return -ENOTCONN;
+       }
+       atomic_inc(&fs_info->scrub_cancel_req);
+       while (atomic_read(&fs_info->scrubs_running)) {
+               mutex_unlock(&fs_info->scrub_lock);
+               wait_event(fs_info->scrub_pause_wait,
+                          atomic_read(&fs_info->scrubs_running) == 0);
+               mutex_lock(&fs_info->scrub_lock);
+       }
+       atomic_dec(&fs_info->scrub_cancel_req);
+       mutex_unlock(&fs_info->scrub_lock);
+       return 0;
+ }
+ int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev)
+ {
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct scrub_dev *sdev;
+       mutex_lock(&fs_info->scrub_lock);
+       sdev = dev->scrub_device;
+       if (!sdev) {
+               mutex_unlock(&fs_info->scrub_lock);
+               return -ENOTCONN;
+       }
+       atomic_inc(&sdev->cancel_req);
+       while (dev->scrub_device) {
+               mutex_unlock(&fs_info->scrub_lock);
+               wait_event(fs_info->scrub_pause_wait,
+                          dev->scrub_device == NULL);
+               mutex_lock(&fs_info->scrub_lock);
+       }
+       mutex_unlock(&fs_info->scrub_lock);
+       return 0;
+ }
+ int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid)
+ {
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_device *dev;
+       int ret;
+       /*
+        * we have to hold the device_list_mutex here so the device
+        * does not go away in cancel_dev. FIXME: find a better solution
+        */
+       mutex_lock(&fs_info->fs_devices->device_list_mutex);
+       dev = btrfs_find_device(root, devid, NULL, NULL);
+       if (!dev) {
+               mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+               return -ENODEV;
+       }
+       ret = btrfs_scrub_cancel_dev(root, dev);
+       mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+       return ret;
+ }
+ int btrfs_scrub_progress(struct btrfs_root *root, u64 devid,
+                        struct btrfs_scrub_progress *progress)
+ {
+       struct btrfs_device *dev;
+       struct scrub_dev *sdev = NULL;
+       mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+       dev = btrfs_find_device(root, devid, NULL, NULL);
+       if (dev)
+               sdev = dev->scrub_device;
+       if (sdev)
+               memcpy(progress, &sdev->stat, sizeof(*progress));
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+       return dev ? (sdev ? 0 : -ENOTCONN) : -ENODEV;
+ }
diff --combined fs/btrfs/transaction.c
@@@ -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
  
@@@ -81,7 -80,8 +81,7 @@@ static noinline int join_transaction(st
                INIT_LIST_HEAD(&cur_trans->pending_snapshots);
                list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
                extent_io_tree_init(&cur_trans->dirty_pages,
 -                                   root->fs_info->btree_inode->i_mapping,
 -                                   GFP_NOFS);
 +                                   root->fs_info->btree_inode->i_mapping);
                spin_lock(&root->fs_info->new_trans_lock);
                root->fs_info->running_transaction = cur_trans;
                spin_unlock(&root->fs_info->new_trans_lock);
@@@ -347,6 -347,49 +347,6 @@@ out_unlock
        return ret;
  }
  
 -#if 0
 -/*
 - * rate limit against the drop_snapshot code.  This helps to slow down new
 - * operations if the drop_snapshot code isn't able to keep up.
 - */
 -static void throttle_on_drops(struct btrfs_root *root)
 -{
 -      struct btrfs_fs_info *info = root->fs_info;
 -      int harder_count = 0;
 -
 -harder:
 -      if (atomic_read(&info->throttles)) {
 -              DEFINE_WAIT(wait);
 -              int thr;
 -              thr = atomic_read(&info->throttle_gen);
 -
 -              do {
 -                      prepare_to_wait(&info->transaction_throttle,
 -                                      &wait, TASK_UNINTERRUPTIBLE);
 -                      if (!atomic_read(&info->throttles)) {
 -                              finish_wait(&info->transaction_throttle, &wait);
 -                              break;
 -                      }
 -                      schedule();
 -                      finish_wait(&info->transaction_throttle, &wait);
 -              } while (thr == atomic_read(&info->throttle_gen));
 -              harder_count++;
 -
 -              if (root->fs_info->total_ref_cache_size > 1 * 1024 * 1024 &&
 -                  harder_count < 2)
 -                      goto harder;
 -
 -              if (root->fs_info->total_ref_cache_size > 5 * 1024 * 1024 &&
 -                  harder_count < 10)
 -                      goto harder;
 -
 -              if (root->fs_info->total_ref_cache_size > 10 * 1024 * 1024 &&
 -                  harder_count < 20)
 -                      goto harder;
 -      }
 -}
 -#endif
 -
  void btrfs_throttle(struct btrfs_root *root)
  {
        mutex_lock(&root->fs_info->trans_mutex);
@@@ -444,40 -487,19 +444,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);
  }
  
  /*
@@@ -738,14 -760,8 +738,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);
                        }
@@@ -793,6 -809,97 +793,6 @@@ int btrfs_defrag_root(struct btrfs_roo
        return ret;
  }
  
 -#if 0
 -/*
 - * when dropping snapshots, we generate a ton of delayed refs, and it makes
 - * sense not to join the transaction while it is trying to flush the current
 - * queue of delayed refs out.
 - *
 - * This is used by the drop snapshot code only
 - */
 -static noinline int wait_transaction_pre_flush(struct btrfs_fs_info *info)
 -{
 -      DEFINE_WAIT(wait);
 -
 -      mutex_lock(&info->trans_mutex);
 -      while (info->running_transaction &&
 -             info->running_transaction->delayed_refs.flushing) {
 -              prepare_to_wait(&info->transaction_wait, &wait,
 -                              TASK_UNINTERRUPTIBLE);
 -              mutex_unlock(&info->trans_mutex);
 -
 -              schedule();
 -
 -              mutex_lock(&info->trans_mutex);
 -              finish_wait(&info->transaction_wait, &wait);
 -      }
 -      mutex_unlock(&info->trans_mutex);
 -      return 0;
 -}
 -
 -/*
 - * Given a list of roots that need to be deleted, call btrfs_drop_snapshot on
 - * all of them
 - */
 -int btrfs_drop_dead_root(struct btrfs_root *root)
 -{
 -      struct btrfs_trans_handle *trans;
 -      struct btrfs_root *tree_root = root->fs_info->tree_root;
 -      unsigned long nr;
 -      int ret;
 -
 -      while (1) {
 -              /*
 -               * we don't want to jump in and create a bunch of
 -               * delayed refs if the transaction is starting to close
 -               */
 -              wait_transaction_pre_flush(tree_root->fs_info);
 -              trans = btrfs_start_transaction(tree_root, 1);
 -
 -              /*
 -               * we've joined a transaction, make sure it isn't
 -               * closing right now
 -               */
 -              if (trans->transaction->delayed_refs.flushing) {
 -                      btrfs_end_transaction(trans, tree_root);
 -                      continue;
 -              }
 -
 -              ret = btrfs_drop_snapshot(trans, root);
 -              if (ret != -EAGAIN)
 -                      break;
 -
 -              ret = btrfs_update_root(trans, tree_root,
 -                                      &root->root_key,
 -                                      &root->root_item);
 -              if (ret)
 -                      break;
 -
 -              nr = trans->blocks_used;
 -              ret = btrfs_end_transaction(trans, tree_root);
 -              BUG_ON(ret);
 -
 -              btrfs_btree_balance_dirty(tree_root, nr);
 -              cond_resched();
 -      }
 -      BUG_ON(ret);
 -
 -      ret = btrfs_del_root(trans, tree_root, &root->root_key);
 -      BUG_ON(ret);
 -
 -      nr = trans->blocks_used;
 -      ret = btrfs_end_transaction(trans, tree_root);
 -      BUG_ON(ret);
 -
 -      free_extent_buffer(root->node);
 -      free_extent_buffer(root->commit_root);
 -      kfree(root);
 -
 -      btrfs_btree_balance_dirty(tree_root, nr);
 -      return ret;
 -}
 -#endif
 -
  /*
   * new snapshots need to be created at a very specific time in the
   * transaction commit.  This does the actual creation
@@@ -823,7 -930,7 +823,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,
 -                              parent_inode->i_ino, &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);
@@@ -930,14 -1037,6 +930,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);
        }
@@@ -1191,9 -1290,6 +1191,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);
  
        WARN_ON(cur_trans != trans->transaction);
  
+       btrfs_scrub_pause(root);
        /* btrfs_commit_tree_roots is responsible for getting the
         * various roots consistent with each other.  Every pointer
         * in the tree of tree roots has to point to the most up to date
  
        mutex_unlock(&root->fs_info->trans_mutex);
  
+       btrfs_scrub_continue(root);
        if (current->journal_info == trans)
                current->journal_info = NULL;
  
@@@ -1339,8 -1435,6 +1342,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
@@@ -333,13 -333,13 +333,13 @@@ static noinline int overwrite_item(stru
                        goto insert;
  
                if (item_size == 0) {
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        return 0;
                }
                dst_copy = kmalloc(item_size, GFP_NOFS);
                src_copy = kmalloc(item_size, GFP_NOFS);
                if (!dst_copy || !src_copy) {
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        kfree(dst_copy);
                        kfree(src_copy);
                        return -ENOMEM;
                 * sync
                 */
                if (ret == 0) {
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        return 0;
                }
  
        }
  insert:
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        /* try to insert the key into the destination tree */
        ret = btrfs_insert_empty_item(trans, root, path,
                                      key, item_size);
        }
  no_copy:
        btrfs_mark_buffer_dirty(path->nodes[0]);
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        return 0;
  }
  
@@@ -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 &&
                 * we don't have to do anything
                 */
                if (memcmp(&cmp1, &cmp2, sizeof(cmp1)) == 0) {
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        goto out;
                }
        }
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
  
        saved_nbytes = inode_get_bytes(inode);
        /* drop any overlapping extents */
                                                key->objectid, offset, &ins);
                                BUG_ON(ret);
                        }
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
  
                        if (btrfs_file_extent_compression(eb, item)) {
                                csum_start = ins.objectid;
  
                        ret = btrfs_lookup_csums_range(root->log_root,
                                                csum_start, csum_end - 1,
-                                               &ordered_sums);
+                                               &ordered_sums, 0);
                        BUG_ON(ret);
                        while (!list_empty(&ordered_sums)) {
                                struct btrfs_ordered_sum *sums;
                                kfree(sums);
                        }
                } else {
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                }
        } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
                /* inline extents are easy, we just overwrite them */
@@@ -675,7 -675,7 +675,7 @@@ static noinline int drop_one_dir_item(s
                return -ENOMEM;
  
        read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len);
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
  
        inode = read_one_inode(root, location.objectid);
        BUG_ON(!inode);
@@@ -713,7 -713,7 +713,7 @@@ static noinline int inode_in_dir(struc
                        goto out;
        } else
                goto out;
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
  
        di = btrfs_lookup_dir_item(NULL, root, path, dirid, name, name_len, 0);
        if (di && !IS_ERR(di)) {
                goto out;
        match = 1;
  out:
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        return match;
  }
  
@@@ -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;
                        if (!backref_in_log(log, key, victim_name,
                                            victim_name_len)) {
                                btrfs_inc_nlink(inode);
 -                              btrfs_release_path(root, path);
 +                              btrfs_release_path(path);
  
                                ret = btrfs_unlink_inode(trans, root, dir,
                                                         inode, victim_name,
                 */
                search_done = 1;
        }
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
  
  insert:
        /* insert our name */
@@@ -922,7 -922,7 +922,7 @@@ out
        BUG_ON(ret);
  
  out_nowrite:
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        iput(dir);
        iput(inode);
        return 0;
@@@ -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 (key.offset == 0)
                        break;
                key.offset--;
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
        }
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        if (nlink != inode->i_nlink) {
                inode->i_nlink = nlink;
                btrfs_update_inode(trans, root, inode);
        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);
@@@ -1053,7 -1052,7 +1053,7 @@@ static noinline int fixup_inode_link_co
                ret = btrfs_del_item(trans, root, path);
                BUG_ON(ret);
  
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
                inode = read_one_inode(root, key.offset);
                BUG_ON(!inode);
  
                 */
                key.offset = (u64)-1;
        }
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        return 0;
  }
  
@@@ -1097,7 -1096,7 +1097,7 @@@ static noinline int link_to_fixup_dir(s
  
        ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
  
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        if (ret == 0) {
                btrfs_inc_nlink(inode);
                btrfs_update_inode(trans, root, inode);
@@@ -1193,7 -1192,7 +1193,7 @@@ static noinline int replay_one_name(str
                exists = 1;
        else
                exists = 0;
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
  
        if (key->type == BTRFS_DIR_ITEM_KEY) {
                dst_di = btrfs_lookup_dir_item(trans, root, path, key->objectid,
        } else {
                BUG();
        }
 -      if (!dst_di || IS_ERR(dst_di)) {
 +      if (IS_ERR_OR_NULL(dst_di)) {
                /* we need a sequence number to insert, so we only
                 * do inserts for the BTRFS_DIR_INDEX_KEY types
                 */
        if (key->type == BTRFS_DIR_INDEX_KEY)
                goto insert;
  out:
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        kfree(name);
        iput(dir);
        return 0;
  
  insert:
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        ret = insert_one_name(trans, root, path, key->objectid, key->offset,
                              name, name_len, log_type, &log_key);
  
@@@ -1364,7 -1363,7 +1364,7 @@@ next
        *end_ret = found_end;
        ret = 0;
  out:
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        return ret;
  }
  
@@@ -1427,10 -1426,10 +1427,10 @@@ again
                                                     dir_key->offset,
                                                     name, name_len, 0);
                }
 -              if (!log_di || IS_ERR(log_di)) {
 +              if (IS_ERR_OR_NULL(log_di)) {
                        btrfs_dir_item_key_to_cpu(eb, di, &location);
 -                      btrfs_release_path(root, path);
 -                      btrfs_release_path(log, log_path);
 +                      btrfs_release_path(path);
 +                      btrfs_release_path(log_path);
                        inode = read_one_inode(root, location.objectid);
                        BUG_ON(!inode);
  
                        ret = 0;
                        goto out;
                }
 -              btrfs_release_path(log, log_path);
 +              btrfs_release_path(log_path);
                kfree(name);
  
                ptr = (unsigned long)(di + 1);
        }
        ret = 0;
  out:
 -      btrfs_release_path(root, path);
 -      btrfs_release_path(log, log_path);
 +      btrfs_release_path(path);
 +      btrfs_release_path(log_path);
        return ret;
  }
  
@@@ -1551,7 -1550,7 +1551,7 @@@ again
                                break;
                        dir_key.offset = found_key.offset + 1;
                }
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
                if (range_end == (u64)-1)
                        break;
                range_start = range_end + 1;
@@@ -1562,11 -1561,11 +1562,11 @@@ next_type
        if (key_type == BTRFS_DIR_LOG_ITEM_KEY) {
                key_type = BTRFS_DIR_LOG_INDEX_KEY;
                dir_key.type = BTRFS_DIR_INDEX_KEY;
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
                goto again;
        }
  out:
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
        btrfs_free_path(log_path);
        iput(dir);
        return ret;
@@@ -2094,7 -2093,9 +2094,9 @@@ int btrfs_sync_log(struct btrfs_trans_h
         * the running transaction open, so a full commit can't hop
         * in and cause problems either.
         */
+       btrfs_scrub_pause_super(root);
        write_ctree_super(trans, root->fs_info->tree_root, 1);
+       btrfs_scrub_continue_super(root);
        ret = 0;
  
        mutex_lock(&root->log_mutex);
@@@ -2198,7 -2199,6 +2200,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);
                bytes_del += name_len;
                BUG_ON(ret);
        }
 -      btrfs_release_path(log, path);
 -      di = btrfs_lookup_dir_index_item(trans, log, path, dir->i_ino,
 +      btrfs_release_path(path);
 +      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);
 +              btrfs_release_path(path);
  
                ret = btrfs_search_slot(trans, log, &key, path, 0, 1);
                if (ret < 0) {
                        btrfs_mark_buffer_dirty(path->nodes[0]);
                } else
                        ret = 0;
 -              btrfs_release_path(log, path);
 +              btrfs_release_path(path);
        }
  fail:
        btrfs_free_path(path);
@@@ -2305,7 -2305,7 +2307,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) {
@@@ -2346,7 -2346,7 +2348,7 @@@ static noinline int insert_dir_log_key(
                              struct btrfs_dir_log_item);
        btrfs_set_dir_log_end(path->nodes[0], item, last_offset);
        btrfs_mark_buffer_dirty(path->nodes[0]);
 -      btrfs_release_path(log, path);
 +      btrfs_release_path(path);
        return 0;
  }
  
@@@ -2371,14 -2371,13 +2373,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(path);
                ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0);
                if (ret < 0) {
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(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]);
                        }
                }
        }
 -      btrfs_release_path(root, path);
 +      btrfs_release_path(path);
  
        /* find the first key from this transaction again */
        ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 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;
                }
                }
        }
  done:
 -      btrfs_release_path(root, path);
 -      btrfs_release_path(log, dst_path);
 +      btrfs_release_path(path);
 +      btrfs_release_path(dst_path);
  
        if (err == 0) {
                *last_offset_ret = last_offset;
                 * 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;
        }
@@@ -2588,9 -2590,9 +2590,9 @@@ static int drop_objectid_items(struct b
  
                ret = btrfs_del_item(trans, log, path);
                BUG_ON(ret);
 -              btrfs_release_path(log, path);
 +              btrfs_release_path(path);
        }
 -      btrfs_release_path(log, path);
 +      btrfs_release_path(path);
        return ret;
  }
  
@@@ -2689,14 -2691,14 +2691,14 @@@ static noinline int copy_items(struct b
                                ret = btrfs_lookup_csums_range(
                                                log->fs_info->csum_root,
                                                ds + cs, ds + cs + cl - 1,
-                                               &ordered_sums);
+                                               &ordered_sums, 0);
                                BUG_ON(ret);
                        }
                }
        }
  
        btrfs_mark_buffer_dirty(dst_path->nodes[0]);
 -      btrfs_release_path(log, dst_path);
 +      btrfs_release_path(dst_path);
        kfree(ins_data);
  
        /*
@@@ -2745,7 -2747,6 +2747,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;
@@@ -2852,7 -2847,7 +2854,7 @@@ next_slot
                        }
                        ins_nr = 0;
                }
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
  
                if (min_key.offset < (u64)-1)
                        min_key.offset++;
        }
        WARN_ON(ins_nr);
        if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) {
 -              btrfs_release_path(root, path);
 -              btrfs_release_path(log, dst_path);
 +              btrfs_release_path(path);
 +              btrfs_release_path(dst_path);
                ret = log_directory_changes(trans, root, inode, path, dst_path);
                if (ret) {
                        err = ret;
@@@ -3143,7 -3138,7 +3145,7 @@@ again
                }
                btrfs_item_key_to_cpu(path->nodes[0], &found_key,
                                      path->slots[0]);
 -              btrfs_release_path(log_root_tree, path);
 +              btrfs_release_path(path);
                if (found_key.objectid != BTRFS_TREE_LOG_OBJECTID)
                        break;
  
                if (found_key.offset == 0)
                        break;
        }
 -      btrfs_release_path(log_root_tree, path);
 +      btrfs_release_path(path);
  
        /* step one is to pin it all, step two is to replay just inodes */
        if (wc.pin) {
diff --combined fs/btrfs/volumes.c
@@@ -38,12 -38,19 +38,9 @@@ static int init_first_rw_device(struct 
                                struct btrfs_device *device);
  static int btrfs_relocate_sys_chunks(struct btrfs_root *root);
  
- #define map_lookup_size(n) (sizeof(struct map_lookup) + \
-                           (sizeof(struct btrfs_bio_stripe) * (n)))
  static DEFINE_MUTEX(uuid_mutex);
  static LIST_HEAD(fs_uuids);
  
 -void btrfs_lock_volumes(void)
 -{
 -      mutex_lock(&uuid_mutex);
 -}
 -
 -void btrfs_unlock_volumes(void)
 -{
 -      mutex_unlock(&uuid_mutex);
 -}
 -
  static void lock_chunks(struct btrfs_root *root)
  {
        mutex_lock(&root->fs_info->chunk_mutex);
@@@ -141,25 -148,22 +138,25 @@@ static noinline int run_scheduled_bios(
        struct bio *cur;
        int again = 0;
        unsigned long num_run;
 -      unsigned long num_sync_run;
        unsigned long batch_run = 0;
        unsigned long limit;
        unsigned long last_waited = 0;
        int force_reg = 0;
 +      struct blk_plug plug;
 +
 +      /*
 +       * this function runs all the bios we've collected for
 +       * a particular device.  We don't want to wander off to
 +       * another device without first sending all of these down.
 +       * So, setup a plug here and finish it off before we return
 +       */
 +      blk_start_plug(&plug);
  
        bdi = blk_get_backing_dev_info(device->bdev);
        fs_info = device->dev_root->fs_info;
        limit = btrfs_async_submit_limit(fs_info);
        limit = limit * 2 / 3;
  
 -      /* we want to make sure that every time we switch from the sync
 -       * list to the normal list, we unplug
 -       */
 -      num_sync_run = 0;
 -
  loop:
        spin_lock(&device->io_lock);
  
@@@ -205,6 -209,15 +202,6 @@@ loop_lock
  
        spin_unlock(&device->io_lock);
  
 -      /*
 -       * if we're doing the regular priority list, make sure we unplug
 -       * for any high prio bios we've sent down
 -       */
 -      if (pending_bios == &device->pending_bios && num_sync_run > 0) {
 -              num_sync_run = 0;
 -              blk_run_backing_dev(bdi, NULL);
 -      }
 -
        while (pending) {
  
                rmb();
  
                BUG_ON(atomic_read(&cur->bi_cnt) == 0);
  
 -              if (cur->bi_rw & REQ_SYNC)
 -                      num_sync_run++;
 -
                submit_bio(cur->bi_rw, cur);
                num_run++;
                batch_run++;
 -              if (need_resched()) {
 -                      if (num_sync_run) {
 -                              blk_run_backing_dev(bdi, NULL);
 -                              num_sync_run = 0;
 -                      }
 +              if (need_resched())
                        cond_resched();
 -              }
  
                /*
                 * we made progress, there is more work to do and the bdi
                                 * against it before looping
                                 */
                                last_waited = ioc->last_waited;
 -                              if (need_resched()) {
 -                                      if (num_sync_run) {
 -                                              blk_run_backing_dev(bdi, NULL);
 -                                              num_sync_run = 0;
 -                                      }
 +                              if (need_resched())
                                        cond_resched();
 -                              }
                                continue;
                        }
                        spin_lock(&device->io_lock);
                }
        }
  
 -      if (num_sync_run) {
 -              num_sync_run = 0;
 -              blk_run_backing_dev(bdi, NULL);
 -      }
 -      /*
 -       * IO has already been through a long path to get here.  Checksumming,
 -       * async helper threads, perhaps compression.  We've done a pretty
 -       * good job of collecting a batch of IO and should just unplug
 -       * the device right away.
 -       *
 -       * This will help anyone who is waiting on the IO, they might have
 -       * already unplugged, but managed to do so before the bio they
 -       * cared about found its way down here.
 -       */
 -      blk_run_backing_dev(bdi, NULL);
 -
        cond_resched();
        if (again)
                goto loop;
        spin_unlock(&device->io_lock);
  
  done:
 +      blk_finish_plug(&plug);
        return 0;
  }
  
@@@ -805,7 -846,10 +802,7 @@@ int find_free_dev_extent(struct btrfs_t
        /* we don't want to overwrite the superblock on the drive,
         * so we make sure to start at an offset of at least 1MB
         */
 -      search_start = 1024 * 1024;
 -
 -      if (root->fs_info->alloc_start + num_bytes <= search_end)
 -              search_start = max(root->fs_info->alloc_start, search_start);
 +      search_start = max(root->fs_info->alloc_start, 1024ull * 1024);
  
        max_hole_start = search_start;
        max_hole_size = 0;
@@@ -1287,6 -1331,7 +1284,7 @@@ int btrfs_rm_device(struct btrfs_root *
                goto error_undo;
  
        device->in_fs_metadata = 0;
+       btrfs_scrub_cancel_dev(root, device);
  
        /*
         * the device list mutex makes sure that we don't change
@@@ -1462,7 -1507,7 +1460,7 @@@ next_slot
                                goto error;
                        leaf = path->nodes[0];
                        btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        continue;
                }
  
@@@ -1934,7 -1979,7 +1932,7 @@@ again
                chunk = btrfs_item_ptr(leaf, path->slots[0],
                                       struct btrfs_chunk);
                chunk_type = btrfs_chunk_type(leaf, chunk);
 -              btrfs_release_path(chunk_root, path);
 +              btrfs_release_path(path);
  
                if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) {
                        ret = btrfs_relocate_chunk(chunk_root, chunk_tree,
@@@ -2052,7 -2097,7 +2050,7 @@@ int btrfs_balance(struct btrfs_root *de
                if (found_key.offset == 0)
                        break;
  
 -              btrfs_release_path(chunk_root, path);
 +              btrfs_release_path(path);
                ret = btrfs_relocate_chunk(chunk_root,
                                           chunk_root->root_key.objectid,
                                           found_key.objectid,
@@@ -2124,7 -2169,7 +2122,7 @@@ again
                        goto done;
                if (ret) {
                        ret = 0;
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        break;
                }
  
                btrfs_item_key_to_cpu(l, &key, path->slots[0]);
  
                if (key.objectid != device->devid) {
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        break;
                }
  
                length = btrfs_dev_extent_length(l, dev_extent);
  
                if (key.offset + length <= new_size) {
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        break;
                }
  
                chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent);
                chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent);
                chunk_offset = btrfs_dev_extent_chunk_offset(l, dev_extent);
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
  
                ret = btrfs_relocate_chunk(root, chunk_tree, chunk_objectid,
                                           chunk_offset);
@@@ -2224,204 -2269,275 +2222,204 @@@ static int btrfs_add_system_chunk(struc
        return 0;
  }
  
 -static noinline u64 chunk_bytes_by_type(u64 type, u64 calc_size,
 -                                      int num_stripes, int sub_stripes)
 +/*
 + * sort the devices in descending order by max_avail, total_avail
 + */
 +static int btrfs_cmp_device_info(const void *a, const void *b)
  {
 -      if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP))
 -              return calc_size;
 -      else if (type & BTRFS_BLOCK_GROUP_RAID10)
 -              return calc_size * (num_stripes / sub_stripes);
 -      else
 -              return calc_size * num_stripes;
 -}
 +      const struct btrfs_device_info *di_a = a;
 +      const struct btrfs_device_info *di_b = b;
  
 -/* Used to sort the devices by max_avail(descending sort) */
 -int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2)
 -{
 -      if (((struct btrfs_device_info *)dev_info1)->max_avail >
 -          ((struct btrfs_device_info *)dev_info2)->max_avail)
 +      if (di_a->max_avail > di_b->max_avail)
                return -1;
 -      else if (((struct btrfs_device_info *)dev_info1)->max_avail <
 -               ((struct btrfs_device_info *)dev_info2)->max_avail)
 +      if (di_a->max_avail < di_b->max_avail)
                return 1;
 -      else
 -              return 0;
 +      if (di_a->total_avail > di_b->total_avail)
 +              return -1;
 +      if (di_a->total_avail < di_b->total_avail)
 +              return 1;
 +      return 0;
  }
  
 -static int __btrfs_calc_nstripes(struct btrfs_fs_devices *fs_devices, u64 type,
 -                               int *num_stripes, int *min_stripes,
 -                               int *sub_stripes)
 +static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 +                             struct btrfs_root *extent_root,
 +                             struct map_lookup **map_ret,
 +                             u64 *num_bytes_out, u64 *stripe_size_out,
 +                             u64 start, u64 type)
  {
 -      *num_stripes = 1;
 -      *min_stripes = 1;
 -      *sub_stripes = 0;
 +      struct btrfs_fs_info *info = extent_root->fs_info;
 +      struct btrfs_fs_devices *fs_devices = info->fs_devices;
 +      struct list_head *cur;
 +      struct map_lookup *map = NULL;
 +      struct extent_map_tree *em_tree;
 +      struct extent_map *em;
 +      struct btrfs_device_info *devices_info = NULL;
 +      u64 total_avail;
 +      int num_stripes;        /* total number of stripes to allocate */
 +      int sub_stripes;        /* sub_stripes info for map */
 +      int dev_stripes;        /* stripes per dev */
 +      int devs_max;           /* max devs to use */
 +      int devs_min;           /* min devs needed */
 +      int devs_increment;     /* ndevs has to be a multiple of this */
 +      int ncopies;            /* how many copies to data has */
 +      int ret;
 +      u64 max_stripe_size;
 +      u64 max_chunk_size;
 +      u64 stripe_size;
 +      u64 num_bytes;
 +      int ndevs;
 +      int i;
 +      int j;
  
 -      if (type & (BTRFS_BLOCK_GROUP_RAID0)) {
 -              *num_stripes = fs_devices->rw_devices;
 -              *min_stripes = 2;
 -      }
 -      if (type & (BTRFS_BLOCK_GROUP_DUP)) {
 -              *num_stripes = 2;
 -              *min_stripes = 2;
 -      }
 -      if (type & (BTRFS_BLOCK_GROUP_RAID1)) {
 -              if (fs_devices->rw_devices < 2)
 -                      return -ENOSPC;
 -              *num_stripes = 2;
 -              *min_stripes = 2;
 -      }
 -      if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
 -              *num_stripes = fs_devices->rw_devices;
 -              if (*num_stripes < 4)
 -                      return -ENOSPC;
 -              *num_stripes &= ~(u32)1;
 -              *sub_stripes = 2;
 -              *min_stripes = 4;
 +      if ((type & BTRFS_BLOCK_GROUP_RAID1) &&
 +          (type & BTRFS_BLOCK_GROUP_DUP)) {
 +              WARN_ON(1);
 +              type &= ~BTRFS_BLOCK_GROUP_DUP;
        }
  
 -      return 0;
 -}
 +      if (list_empty(&fs_devices->alloc_list))
 +              return -ENOSPC;
  
 -static u64 __btrfs_calc_stripe_size(struct btrfs_fs_devices *fs_devices,
 -                                  u64 proposed_size, u64 type,
 -                                  int num_stripes, int small_stripe)
 -{
 -      int min_stripe_size = 1 * 1024 * 1024;
 -      u64 calc_size = proposed_size;
 -      u64 max_chunk_size = calc_size;
 -      int ncopies = 1;
 +      sub_stripes = 1;
 +      dev_stripes = 1;
 +      devs_increment = 1;
 +      ncopies = 1;
 +      devs_max = 0;   /* 0 == as many as possible */
 +      devs_min = 1;
  
 -      if (type & (BTRFS_BLOCK_GROUP_RAID1 |
 -                  BTRFS_BLOCK_GROUP_DUP |
 -                  BTRFS_BLOCK_GROUP_RAID10))
 +      /*
 +       * define the properties of each RAID type.
 +       * FIXME: move this to a global table and use it in all RAID
 +       * calculation code
 +       */
 +      if (type & (BTRFS_BLOCK_GROUP_DUP)) {
 +              dev_stripes = 2;
 +              ncopies = 2;
 +              devs_max = 1;
 +      } else if (type & (BTRFS_BLOCK_GROUP_RAID0)) {
 +              devs_min = 2;
 +      } else if (type & (BTRFS_BLOCK_GROUP_RAID1)) {
 +              devs_increment = 2;
                ncopies = 2;
 +              devs_max = 2;
 +              devs_min = 2;
 +      } else if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
 +              sub_stripes = 2;
 +              devs_increment = 2;
 +              ncopies = 2;
 +              devs_min = 4;
 +      } else {
 +              devs_max = 1;
 +      }
  
        if (type & BTRFS_BLOCK_GROUP_DATA) {
 -              max_chunk_size = 10 * calc_size;
 -              min_stripe_size = 64 * 1024 * 1024;
 +              max_stripe_size = 1024 * 1024 * 1024;
 +              max_chunk_size = 10 * max_stripe_size;
        } else if (type & BTRFS_BLOCK_GROUP_METADATA) {
 -              max_chunk_size = 256 * 1024 * 1024;
 -              min_stripe_size = 32 * 1024 * 1024;
 +              max_stripe_size = 256 * 1024 * 1024;
 +              max_chunk_size = max_stripe_size;
        } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
 -              calc_size = 8 * 1024 * 1024;
 -              max_chunk_size = calc_size * 2;
 -              min_stripe_size = 1 * 1024 * 1024;
 +              max_stripe_size = 8 * 1024 * 1024;
 +              max_chunk_size = 2 * max_stripe_size;
 +      } else {
 +              printk(KERN_ERR "btrfs: invalid chunk type 0x%llx requested\n",
 +                     type);
 +              BUG_ON(1);
        }
  
        /* we don't want a chunk larger than 10% of writeable space */
        max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 1),
                             max_chunk_size);
  
 -      if (calc_size * num_stripes > max_chunk_size * ncopies) {
 -              calc_size = max_chunk_size * ncopies;
 -              do_div(calc_size, num_stripes);
 -              do_div(calc_size, BTRFS_STRIPE_LEN);
 -              calc_size *= BTRFS_STRIPE_LEN;
 -      }
 +      devices_info = kzalloc(sizeof(*devices_info) * fs_devices->rw_devices,
 +                             GFP_NOFS);
 +      if (!devices_info)
 +              return -ENOMEM;
  
 -      /* we don't want tiny stripes */
 -      if (!small_stripe)
 -              calc_size = max_t(u64, min_stripe_size, calc_size);
 +      cur = fs_devices->alloc_list.next;
  
        /*
 -       * we're about to do_div by the BTRFS_STRIPE_LEN so lets make sure
 -       * we end up with something bigger than a stripe
 +       * in the first pass through the devices list, we gather information
 +       * about the available holes on each device.
         */
 -      calc_size = max_t(u64, calc_size, BTRFS_STRIPE_LEN);
 -
 -      do_div(calc_size, BTRFS_STRIPE_LEN);
 -      calc_size *= BTRFS_STRIPE_LEN;
 +      ndevs = 0;
 +      while (cur != &fs_devices->alloc_list) {
 +              struct btrfs_device *device;
 +              u64 max_avail;
 +              u64 dev_offset;
  
 -      return calc_size;
 -}
 -
 -static struct map_lookup *__shrink_map_lookup_stripes(struct map_lookup *map,
 -                                                    int num_stripes)
 -{
 -      struct map_lookup *new;
 -      size_t len = map_lookup_size(num_stripes);
 -
 -      BUG_ON(map->num_stripes < num_stripes);
 -
 -      if (map->num_stripes == num_stripes)
 -              return map;
 -
 -      new = kmalloc(len, GFP_NOFS);
 -      if (!new) {
 -              /* just change map->num_stripes */
 -              map->num_stripes = num_stripes;
 -              return map;
 -      }
 -
 -      memcpy(new, map, len);
 -      new->num_stripes = num_stripes;
 -      kfree(map);
 -      return new;
 -}
 -
 -/*
 - * helper to allocate device space from btrfs_device_info, in which we stored
 - * max free space information of every device. It is used when we can not
 - * allocate chunks by default size.
 - *
 - * By this helper, we can allocate a new chunk as larger as possible.
 - */
 -static int __btrfs_alloc_tiny_space(struct btrfs_trans_handle *trans,
 -                                  struct btrfs_fs_devices *fs_devices,
 -                                  struct btrfs_device_info *devices,
 -                                  int nr_device, u64 type,
 -                                  struct map_lookup **map_lookup,
 -                                  int min_stripes, u64 *stripe_size)
 -{
 -      int i, index, sort_again = 0;
 -      int min_devices = min_stripes;
 -      u64 max_avail, min_free;
 -      struct map_lookup *map = *map_lookup;
 -      int ret;
 +              device = list_entry(cur, struct btrfs_device, dev_alloc_list);
  
 -      if (nr_device < min_stripes)
 -              return -ENOSPC;
 +              cur = cur->next;
  
 -      btrfs_descending_sort_devices(devices, nr_device);
 +              if (!device->writeable) {
 +                      printk(KERN_ERR
 +                             "btrfs: read-only device in alloc_list\n");
 +                      WARN_ON(1);
 +                      continue;
 +              }
  
 -      max_avail = devices[0].max_avail;
 -      if (!max_avail)
 -              return -ENOSPC;
 +              if (!device->in_fs_metadata)
 +                      continue;
  
 -      for (i = 0; i < nr_device; i++) {
 -              /*
 -               * if dev_offset = 0, it means the free space of this device
 -               * is less than what we need, and we didn't search max avail
 -               * extent on this device, so do it now.
 +              if (device->total_bytes > device->bytes_used)
 +                      total_avail = device->total_bytes - device->bytes_used;
 +              else
 +                      total_avail = 0;
 +              /* avail is off by max(alloc_start, 1MB), but that is the same
 +               * for all devices, so it doesn't hurt the sorting later on
                 */
 -              if (!devices[i].dev_offset) {
 -                      ret = find_free_dev_extent(trans, devices[i].dev,
 -                                                 max_avail,
 -                                                 &devices[i].dev_offset,
 -                                                 &devices[i].max_avail);
 -                      if (ret != 0 && ret != -ENOSPC)
 -                              return ret;
 -                      sort_again = 1;
 -              }
 -      }
  
 -      /* we update the max avail free extent of each devices, sort again */
 -      if (sort_again)
 -              btrfs_descending_sort_devices(devices, nr_device);
 -
 -      if (type & BTRFS_BLOCK_GROUP_DUP)
 -              min_devices = 1;
 +              ret = find_free_dev_extent(trans, device,
 +                                         max_stripe_size * dev_stripes,
 +                                         &dev_offset, &max_avail);
 +              if (ret && ret != -ENOSPC)
 +                      goto error;
  
 -      if (!devices[min_devices - 1].max_avail)
 -              return -ENOSPC;
 +              if (ret == 0)
 +                      max_avail = max_stripe_size * dev_stripes;
  
 -      max_avail = devices[min_devices - 1].max_avail;
 -      if (type & BTRFS_BLOCK_GROUP_DUP)
 -              do_div(max_avail, 2);
 +              if (max_avail < BTRFS_STRIPE_LEN * dev_stripes)
 +                      continue;
  
 -      max_avail = __btrfs_calc_stripe_size(fs_devices, max_avail, type,
 -                                           min_stripes, 1);
 -      if (type & BTRFS_BLOCK_GROUP_DUP)
 -              min_free = max_avail * 2;
 -      else
 -              min_free = max_avail;
 +              devices_info[ndevs].dev_offset = dev_offset;
 +              devices_info[ndevs].max_avail = max_avail;
 +              devices_info[ndevs].total_avail = total_avail;
 +              devices_info[ndevs].dev = device;
 +              ++ndevs;
 +      }
  
 -      if (min_free > devices[min_devices - 1].max_avail)
 -              return -ENOSPC;
 +      /*
 +       * now sort the devices by hole size / available space
 +       */
 +      sort(devices_info, ndevs, sizeof(struct btrfs_device_info),
 +           btrfs_cmp_device_info, NULL);
  
 -      map = __shrink_map_lookup_stripes(map, min_stripes);
 -      *stripe_size = max_avail;
 +      /* round down to number of usable stripes */
 +      ndevs -= ndevs % devs_increment;
  
 -      index = 0;
 -      for (i = 0; i < min_stripes; i++) {
 -              map->stripes[i].dev = devices[index].dev;
 -              map->stripes[i].physical = devices[index].dev_offset;
 -              if (type & BTRFS_BLOCK_GROUP_DUP) {
 -                      i++;
 -                      map->stripes[i].dev = devices[index].dev;
 -                      map->stripes[i].physical = devices[index].dev_offset +
 -                                                 max_avail;
 -              }
 -              index++;
 +      if (ndevs < devs_increment * sub_stripes || ndevs < devs_min) {
 +              ret = -ENOSPC;
 +              goto error;
        }
 -      *map_lookup = map;
  
 -      return 0;
 -}
 -
 -static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 -                             struct btrfs_root *extent_root,
 -                             struct map_lookup **map_ret,
 -                             u64 *num_bytes, u64 *stripe_size,
 -                             u64 start, u64 type)
 -{
 -      struct btrfs_fs_info *info = extent_root->fs_info;
 -      struct btrfs_device *device = NULL;
 -      struct btrfs_fs_devices *fs_devices = info->fs_devices;
 -      struct list_head *cur;
 -      struct map_lookup *map;
 -      struct extent_map_tree *em_tree;
 -      struct extent_map *em;
 -      struct btrfs_device_info *devices_info;
 -      struct list_head private_devs;
 -      u64 calc_size = 1024 * 1024 * 1024;
 -      u64 min_free;
 -      u64 avail;
 -      u64 dev_offset;
 -      int num_stripes;
 -      int min_stripes;
 -      int sub_stripes;
 -      int min_devices;        /* the min number of devices we need */
 -      int i;
 -      int ret;
 -      int index;
 +      if (devs_max && ndevs > devs_max)
 +              ndevs = devs_max;
 +      /*
 +       * the primary goal is to maximize the number of stripes, so use as many
 +       * devices as possible, even if the stripes are not maximum sized.
 +       */
 +      stripe_size = devices_info[ndevs-1].max_avail;
 +      num_stripes = ndevs * dev_stripes;
  
 -      if ((type & BTRFS_BLOCK_GROUP_RAID1) &&
 -          (type & BTRFS_BLOCK_GROUP_DUP)) {
 -              WARN_ON(1);
 -              type &= ~BTRFS_BLOCK_GROUP_DUP;
 +      if (stripe_size * num_stripes > max_chunk_size * ncopies) {
 +              stripe_size = max_chunk_size * ncopies;
 +              do_div(stripe_size, num_stripes);
        }
 -      if (list_empty(&fs_devices->alloc_list))
 -              return -ENOSPC;
 -
 -      ret = __btrfs_calc_nstripes(fs_devices, type, &num_stripes,
 -                                  &min_stripes, &sub_stripes);
 -      if (ret)
 -              return ret;
  
 -      devices_info = kzalloc(sizeof(*devices_info) * fs_devices->rw_devices,
 -                             GFP_NOFS);
 -      if (!devices_info)
 -              return -ENOMEM;
 +      do_div(stripe_size, dev_stripes);
 +      do_div(stripe_size, BTRFS_STRIPE_LEN);
 +      stripe_size *= BTRFS_STRIPE_LEN;
  
        map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
        if (!map) {
        }
        map->num_stripes = num_stripes;
  
 -      cur = fs_devices->alloc_list.next;
 -      index = 0;
 -      i = 0;
 -
 -      calc_size = __btrfs_calc_stripe_size(fs_devices, calc_size, type,
 -                                           num_stripes, 0);
 -
 -      if (type & BTRFS_BLOCK_GROUP_DUP) {
 -              min_free = calc_size * 2;
 -              min_devices = 1;
 -      } else {
 -              min_free = calc_size;
 -              min_devices = min_stripes;
 -      }
 -
 -      INIT_LIST_HEAD(&private_devs);
 -      while (index < num_stripes) {
 -              device = list_entry(cur, struct btrfs_device, dev_alloc_list);
 -              BUG_ON(!device->writeable);
 -              if (device->total_bytes > device->bytes_used)
 -                      avail = device->total_bytes - device->bytes_used;
 -              else
 -                      avail = 0;
 -              cur = cur->next;
 -
 -              if (device->in_fs_metadata && avail >= min_free) {
 -                      ret = find_free_dev_extent(trans, device, min_free,
 -                                                 &devices_info[i].dev_offset,
 -                                                 &devices_info[i].max_avail);
 -                      if (ret == 0) {
 -                              list_move_tail(&device->dev_alloc_list,
 -                                             &private_devs);
 -                              map->stripes[index].dev = device;
 -                              map->stripes[index].physical =
 -                                              devices_info[i].dev_offset;
 -                              index++;
 -                              if (type & BTRFS_BLOCK_GROUP_DUP) {
 -                                      map->stripes[index].dev = device;
 -                                      map->stripes[index].physical =
 -                                              devices_info[i].dev_offset +
 -                                              calc_size;
 -                                      index++;
 -                              }
 -                      } else if (ret != -ENOSPC)
 -                              goto error;
 -
 -                      devices_info[i].dev = device;
 -                      i++;
 -              } else if (device->in_fs_metadata &&
 -                         avail >= BTRFS_STRIPE_LEN) {
 -                      devices_info[i].dev = device;
 -                      devices_info[i].max_avail = avail;
 -                      i++;
 -              }
 -
 -              if (cur == &fs_devices->alloc_list)
 -                      break;
 -      }
 -
 -      list_splice(&private_devs, &fs_devices->alloc_list);
 -      if (index < num_stripes) {
 -              if (index >= min_stripes) {
 -                      num_stripes = index;
 -                      if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
 -                              num_stripes /= sub_stripes;
 -                              num_stripes *= sub_stripes;
 -                      }
 -
 -                      map = __shrink_map_lookup_stripes(map, num_stripes);
 -              } else if (i >= min_devices) {
 -                      ret = __btrfs_alloc_tiny_space(trans, fs_devices,
 -                                                     devices_info, i, type,
 -                                                     &map, min_stripes,
 -                                                     &calc_size);
 -                      if (ret)
 -                              goto error;
 -              } else {
 -                      ret = -ENOSPC;
 -                      goto error;
 +      for (i = 0; i < ndevs; ++i) {
 +              for (j = 0; j < dev_stripes; ++j) {
 +                      int s = i * dev_stripes + j;
 +                      map->stripes[s].dev = devices_info[i].dev;
 +                      map->stripes[s].physical = devices_info[i].dev_offset +
 +                                                 j * stripe_size;
                }
        }
        map->sector_size = extent_root->sectorsize;
        map->sub_stripes = sub_stripes;
  
        *map_ret = map;
 -      *stripe_size = calc_size;
 -      *num_bytes = chunk_bytes_by_type(type, calc_size,
 -                                       map->num_stripes, sub_stripes);
 +      num_bytes = stripe_size * (num_stripes / ncopies);
  
 -      trace_btrfs_chunk_alloc(info->chunk_root, map, start, *num_bytes);
 +      *stripe_size_out = stripe_size;
 +      *num_bytes_out = num_bytes;
  
 -      em = alloc_extent_map(GFP_NOFS);
 +      trace_btrfs_chunk_alloc(info->chunk_root, map, start, num_bytes);
 +
 +      em = alloc_extent_map();
        if (!em) {
                ret = -ENOMEM;
                goto error;
        }
        em->bdev = (struct block_device *)map;
        em->start = start;
 -      em->len = *num_bytes;
 +      em->len = num_bytes;
        em->block_start = 0;
        em->block_len = em->len;
  
  
        ret = btrfs_make_block_group(trans, extent_root, 0, type,
                                     BTRFS_FIRST_CHUNK_TREE_OBJECTID,
 -                                   start, *num_bytes);
 +                                   start, num_bytes);
        BUG_ON(ret);
  
 -      index = 0;
 -      while (index < map->num_stripes) {
 -              device = map->stripes[index].dev;
 -              dev_offset = map->stripes[index].physical;
 +      for (i = 0; i < map->num_stripes; ++i) {
 +              struct btrfs_device *device;
 +              u64 dev_offset;
 +
 +              device = map->stripes[i].dev;
 +              dev_offset = map->stripes[i].physical;
  
                ret = btrfs_alloc_dev_extent(trans, device,
                                info->chunk_root->root_key.objectid,
                                BTRFS_FIRST_CHUNK_TREE_OBJECTID,
 -                              start, dev_offset, calc_size);
 +                              start, dev_offset, stripe_size);
                BUG_ON(ret);
 -              index++;
        }
  
        kfree(devices_info);
@@@ -2694,7 -2881,7 +2692,7 @@@ int btrfs_chunk_readonly(struct btrfs_r
  
  void btrfs_mapping_init(struct btrfs_mapping_tree *tree)
  {
 -      extent_map_tree_init(&tree->map_tree, GFP_NOFS);
 +      extent_map_tree_init(&tree->map_tree);
  }
  
  void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree)
@@@ -2760,7 -2947,7 +2758,7 @@@ static int find_live_mirror(struct map_
  static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
                             u64 logical, u64 *length,
                             struct btrfs_multi_bio **multi_ret,
 -                           int mirror_num, struct page *unplug_page)
 +                           int mirror_num)
  {
        struct extent_map *em;
        struct map_lookup *map;
@@@ -2795,6 -2982,11 +2793,6 @@@ again
        em = lookup_extent_mapping(em_tree, logical, *length);
        read_unlock(&em_tree->lock);
  
 -      if (!em && unplug_page) {
 -              kfree(multi);
 -              return 0;
 -      }
 -
        if (!em) {
                printk(KERN_CRIT "unable to find logical %llu len %llu\n",
                       (unsigned long long)logical,
                *length = em->len - offset;
        }
  
 -      if (!multi_ret && !unplug_page)
 +      if (!multi_ret)
                goto out;
  
        num_stripes = 1;
                                            stripe_nr_end - stripe_nr_orig);
                stripe_index = do_div(stripe_nr, map->num_stripes);
        } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
 -              if (unplug_page || (rw & (REQ_WRITE | REQ_DISCARD)))
 +              if (rw & (REQ_WRITE | REQ_DISCARD))
                        num_stripes = map->num_stripes;
                else if (mirror_num)
                        stripe_index = mirror_num - 1;
                stripe_index = do_div(stripe_nr, factor);
                stripe_index *= map->sub_stripes;
  
 -              if (unplug_page || (rw & REQ_WRITE))
 +              if (rw & REQ_WRITE)
                        num_stripes = map->sub_stripes;
                else if (rw & REQ_DISCARD)
                        num_stripes = min_t(u64, map->sub_stripes *
                }
        } else {
                for (i = 0; i < num_stripes; i++) {
 -                      if (unplug_page) {
 -                              struct btrfs_device *device;
 -                              struct backing_dev_info *bdi;
 -
 -                              device = map->stripes[stripe_index].dev;
 -                              if (device->bdev) {
 -                                      bdi = blk_get_backing_dev_info(device->
 -                                                                     bdev);
 -                                      if (bdi->unplug_io_fn)
 -                                              bdi->unplug_io_fn(bdi,
 -                                                                unplug_page);
 -                              }
 -                      } else {
 -                              multi->stripes[i].physical =
 -                                      map->stripes[stripe_index].physical +
 -                                      stripe_offset +
 -                                      stripe_nr * map->stripe_len;
 -                              multi->stripes[i].dev =
 -                                      map->stripes[stripe_index].dev;
 -                      }
 +                      multi->stripes[i].physical =
 +                              map->stripes[stripe_index].physical +
 +                              stripe_offset +
 +                              stripe_nr * map->stripe_len;
 +                      multi->stripes[i].dev =
 +                              map->stripes[stripe_index].dev;
                        stripe_index++;
                }
        }
@@@ -3034,7 -3240,7 +3032,7 @@@ int btrfs_map_block(struct btrfs_mappin
                      struct btrfs_multi_bio **multi_ret, int mirror_num)
  {
        return __btrfs_map_block(map_tree, rw, logical, length, multi_ret,
 -                               mirror_num, NULL);
 +                               mirror_num);
  }
  
  int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
        return 0;
  }
  
 -int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree,
 -                    u64 logical, struct page *page)
 -{
 -      u64 length = PAGE_CACHE_SIZE;
 -      return __btrfs_map_block(map_tree, READ, logical, &length,
 -                               NULL, 0, page);
 -}
 -
  static void end_bio_multi_stripe(struct bio *bio, int err)
  {
        struct btrfs_multi_bio *multi = bio->bi_private;
@@@ -3344,7 -3558,7 +3342,7 @@@ static int read_one_chunk(struct btrfs_
                free_extent_map(em);
        }
  
 -      em = alloc_extent_map(GFP_NOFS);
 +      em = alloc_extent_map();
        if (!em)
                return -ENOMEM;
        num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
@@@ -3533,6 -3747,15 +3531,6 @@@ static int read_one_dev(struct btrfs_ro
        return ret;
  }
  
 -int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf)
 -{
 -      struct btrfs_dev_item *dev_item;
 -
 -      dev_item = (struct btrfs_dev_item *)offsetof(struct btrfs_super_block,
 -                                                   dev_item);
 -      return read_one_dev(root, buf, dev_item);
 -}
 -
  int btrfs_read_sys_array(struct btrfs_root *root)
  {
        struct btrfs_super_block *super_copy = &root->fs_info->super_copy;
@@@ -3649,7 -3872,7 +3647,7 @@@ again
        }
        if (key.objectid == BTRFS_DEV_ITEMS_OBJECTID) {
                key.objectid = 0;
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
                goto again;
        }
        ret = 0;
diff --combined fs/btrfs/volumes.h
@@@ -85,6 -85,9 +85,9 @@@ struct btrfs_device 
        /* physical drive uuid (or lvm uuid) */
        u8 uuid[BTRFS_UUID_SIZE];
  
+       /* per-device scrub information */
+       struct scrub_dev *scrub_device;
        struct btrfs_work work;
  };
  
@@@ -144,7 -147,6 +147,7 @@@ struct btrfs_device_info 
        struct btrfs_device *dev;
        u64 dev_offset;
        u64 max_avail;
 +      u64 total_avail;
  };
  
  struct map_lookup {
        struct btrfs_bio_stripe stripes[];
  };
  
 -/* Used to sort the devices by max_avail(descending sort) */
 -int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2);
 -
 -/*
 - * sort the devices by max_avail, in which max free extent size of each device
 - * is stored.(Descending Sort)
 - */
 -static inline void btrfs_descending_sort_devices(
 -                                      struct btrfs_device_info *devices,
 -                                      size_t nr_devices)
 -{
 -      sort(devices, nr_devices, sizeof(struct btrfs_device_info),
 -           btrfs_cmp_device_free_bytes, NULL);
 -}
 -
+ #define map_lookup_size(n) (sizeof(struct map_lookup) + \
+                           (sizeof(struct btrfs_bio_stripe) * (n)))
  int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
                                   u64 end, u64 *length);
  
@@@ -182,6 -202,7 +188,6 @@@ void btrfs_mapping_init(struct btrfs_ma
  void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree);
  int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
                  int mirror_num, int async_submit);
 -int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf);
  int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                       fmode_t flags, void *holder);
  int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
@@@ -194,6 -215,8 +200,6 @@@ int btrfs_add_device(struct btrfs_trans
  int btrfs_rm_device(struct btrfs_root *root, char *device_path);
  int btrfs_cleanup_fs_uuids(void);
  int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len);
 -int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree,
 -                    u64 logical, struct page *page);
  int btrfs_grow_device(struct btrfs_trans_handle *trans,
                      struct btrfs_device *device, u64 new_size);
  struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
  int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
  int btrfs_init_new_device(struct btrfs_root *root, char *path);
  int btrfs_balance(struct btrfs_root *dev_root);
 -void btrfs_unlock_volumes(void);
 -void btrfs_lock_volumes(void);
  int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
  int find_free_dev_extent(struct btrfs_trans_handle *trans,
                         struct btrfs_device *device, u64 num_bytes,