Merge branch 'error-handling' into for-linus
authorChris Mason <chris.mason@oracle.com>
Thu, 29 Mar 2012 00:31:37 +0000 (20:31 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 29 Mar 2012 00:31:37 +0000 (20:31 -0400)
Conflicts:
fs/btrfs/ctree.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/inode.c
fs/btrfs/scrub.c

Signed-off-by: Chris Mason <chris.mason@oracle.com>

1  2 
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/inode-item.c
fs/btrfs/inode.c
fs/btrfs/scrub.c
fs/btrfs/volumes.c

@@@ -1023,13 -1025,10 +1038,10 @@@ static noinline int balance_level(struc
                if (btrfs_header_nritems(right) == 0) {
                        clean_tree_block(trans, root, right);
                        btrfs_tree_unlock(right);
-                       wret = del_ptr(trans, root, path, level + 1, pslot +
-                                      1);
-                       if (wret)
-                               ret = wret;
+                       del_ptr(trans, root, path, level + 1, pslot + 1);
                        root_sub_used(root, right->len);
                        btrfs_free_tree_block(trans, root, right, 0, 1, 0);
 -                      free_extent_buffer(right);
 +                      free_extent_buffer_stale(right);
                        right = NULL;
                } else {
                        struct btrfs_disk_key right_key;
        if (btrfs_header_nritems(mid) == 0) {
                clean_tree_block(trans, root, mid);
                btrfs_tree_unlock(mid);
-               wret = del_ptr(trans, root, path, level + 1, pslot);
-               if (wret)
-                       ret = wret;
+               del_ptr(trans, root, path, level + 1, pslot);
                root_sub_used(root, mid->len);
                btrfs_free_tree_block(trans, root, mid, 0, 1, 0);
 -              free_extent_buffer(mid);
 +              free_extent_buffer_stale(mid);
                mid = NULL;
        } else {
                /* update the parent key to reflect our changes */
@@@ -2564,12 -2537,8 +2564,11 @@@ static noinline int __push_leaf_left(st
        u32 old_left_nritems;
        u32 nr;
        int ret = 0;
-       int wret;
        u32 this_item_size;
        u32 old_left_item_size;
 +      struct btrfs_map_token token;
 +
 +      btrfs_init_map_token(&token);
  
        if (empty)
                nr = min(right_nritems, max_slot);
@@@ -2783,12 -2747,7 +2779,10 @@@ static noinline void copy_for_split(str
        int data_copy_size;
        int rt_data_off;
        int i;
-       int ret = 0;
-       int wret;
        struct btrfs_disk_key disk_key;
 +      struct btrfs_map_token token;
 +
 +      btrfs_init_map_token(&token);
  
        nritems = nritems - mid;
        btrfs_set_header_nritems(right, nritems);
@@@ -3621,12 -3545,8 +3594,11 @@@ void setup_items_for_insert(struct btrf
        u32 nritems;
        unsigned int data_end;
        struct btrfs_disk_key disk_key;
-       int ret;
        struct extent_buffer *leaf;
        int slot;
 +      struct btrfs_map_token token;
 +
 +      btrfs_init_map_token(&token);
  
        leaf = path->nodes[0];
        slot = path->slots[0];
@@@ -3835,10 -3740,7 +3794,9 @@@ static noinline void btrfs_del_leaf(str
  
        root_sub_used(root, leaf->len);
  
 +      extent_buffer_get(leaf);
        btrfs_free_tree_block(trans, root, leaf, 0, 1, 0);
 +      free_extent_buffer_stale(leaf);
-       return 0;
  }
  /*
   * delete the item at the leaf level in path.  If that empties
Simple merge
@@@ -332,8 -332,8 +332,8 @@@ static int verify_parent_transid(struc
                return 0;
  
        lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
-                        0, &cached_state, GFP_NOFS);
+                        0, &cached_state);
 -      if (extent_buffer_uptodate(io_tree, eb, cached_state) &&
 +      if (extent_buffer_uptodate(eb) &&
            btrfs_header_generation(eb) == parent_transid) {
                ret = 0;
                goto out;
@@@ -422,10 -409,35 +422,9 @@@ static int csum_dirty_buffer(struct btr
  
        tree = &BTRFS_I(page->mapping->host)->io_tree;
  
 -      if (page->private == EXTENT_PAGE_PRIVATE) {
 -              WARN_ON(1);
 -              goto out;
 -      }
 -      if (!page->private) {
 -              WARN_ON(1);
 -              goto out;
 -      }
 -      len = page->private >> 2;
 -      WARN_ON(len == 0);
 -
 -      eb = alloc_extent_buffer(tree, start, len, page);
 -      if (eb == NULL) {
 -              WARN_ON(1);
 -              ret = -ENOMEM;
 -              goto out;
 -      }
 -      ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE,
 -                                           btrfs_header_generation(eb));
 -      if (ret) {
 -              btrfs_printk(root->fs_info, KERN_WARNING
 -                           "Failed to checksum dirty buffer @ %llu[%lu]\n",
 -                            start, len);
 -              goto err;
 -      }
 -      WARN_ON(!btrfs_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN));
 -
 -      ret = -EIO;
 +      eb = (struct extent_buffer *)page->private;
 +      if (page != eb->pages[0])
 +              return 0;
        found_start = btrfs_header_bytenr(eb);
        if (found_start != start) {
                WARN_ON(1);
@@@ -861,9 -877,6 +873,10 @@@ static int btree_submit_bio_hook(struc
                 * called for a read, do the setup so that checksum validation
                 * can happen in the async kernel threads
                 */
 +              ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info,
 +                                        bio, 1);
-               BUG_ON(ret);
++              if (ret)
++                      return ret;
                return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
                                     mirror_num, 0);
        }
@@@ -1080,9 -1130,10 +1093,9 @@@ struct extent_buffer *read_tree_block(s
  
  }
  
- int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                    struct extent_buffer *buf)
+ void clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+                     struct extent_buffer *buf)
  {
 -      struct inode *btree_inode = root->fs_info->btree_inode;
        if (btrfs_header_generation(buf) ==
            root->fs_info->running_transaction->transid) {
                btrfs_assert_tree_locked(buf);
  
                /* ugh, clear_extent_buffer_dirty needs to lock the page */
                btrfs_set_lock_blocking(buf);
 -              clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree,
 -                                        buf);
 +              clear_extent_buffer_dirty(buf);
        }
-       return 0;
  }
  
- static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
-                       u32 stripesize, struct btrfs_root *root,
-                       struct btrfs_fs_info *fs_info,
-                       u64 objectid)
+ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
+                        u32 stripesize, struct btrfs_root *root,
+                        struct btrfs_fs_info *fs_info,
+                        u64 objectid)
  {
        root->node = NULL;
        root->commit_root = NULL;
@@@ -5017,7 -5072,12 +5072,8 @@@ static int __btrfs_free_extent(struct b
  
                if (is_data) {
                        ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
-                       BUG_ON(ret);
+                       if (ret)
+                               goto abort;
 -              } else {
 -                      invalidate_mapping_pages(info->btree_inode->i_mapping,
 -                           bytenr >> PAGE_CACHE_SHIFT,
 -                           (bytenr + num_bytes - 1) >> PAGE_CACHE_SHIFT);
                }
  
                ret = update_block_group(trans, root, bytenr, num_bytes, 0);
@@@ -5409,12 -5479,45 +5470,13 @@@ search
  have_block_group:
                cached = block_group_cache_done(block_group);
                if (unlikely(!cached)) {
 -                      u64 free_percent;
 -
                        found_uncached_bg = true;
                        ret = cache_block_group(block_group, trans,
 -                                              orig_root, 1);
 -                      BUG_ON(ret < 0); /* -ENOMEM */
 -                      if (block_group->cached == BTRFS_CACHE_FINISHED)
 -                              goto alloc;
 -
 -                      free_percent = btrfs_block_group_used(&block_group->item);
 -                      free_percent *= 100;
 -                      free_percent = div64_u64(free_percent,
 -                                               block_group->key.offset);
 -                      free_percent = 100 - free_percent;
 -                      if (free_percent > ideal_cache_percent &&
 -                          likely(!block_group->ro)) {
 -                              ideal_cache_offset = block_group->key.objectid;
 -                              ideal_cache_percent = free_percent;
 -                      }
 -
 -                      /*
 -                       * The caching workers are limited to 2 threads, so we
 -                       * can queue as much work as we care to.
 -                       */
 -                      if (loop > LOOP_FIND_IDEAL) {
 -                              ret = cache_block_group(block_group, trans,
 -                                                      orig_root, 0);
 -                              BUG_ON(ret); /* -ENOMEM */
 -                      }
 -
 -                      /*
 -                       * If loop is set for cached only, try the next block
 -                       * group.
 -                       */
 -                      if (loop == LOOP_FIND_IDEAL)
 -                              goto loop;
 +                                              orig_root, 0);
-                       BUG_ON(ret);
++                      BUG_ON(ret < 0);
++                      ret = 0;
                }
  
 -alloc:
                if (unlikely(block_group->ro))
                        goto loop;
  
@@@ -54,7 -53,11 +54,12 @@@ struct extent_page_data 
        unsigned int sync_io:1;
  };
  
 +static noinline void flush_write_bio(void *data);
+ static inline struct btrfs_fs_info *
+ tree_fs_info(struct extent_io_tree *tree)
+ {
+       return btrfs_sb(tree->mapping->host->i_sb);
+ }
  
  int __init extent_io_init(void)
  {
@@@ -4211,35 -3833,14 +4254,35 @@@ void free_extent_buffer(struct extent_b
        if (!eb)
                return;
  
 -      if (!atomic_dec_and_test(&eb->refs))
 +      spin_lock(&eb->refs_lock);
 +      if (atomic_read(&eb->refs) == 2 &&
 +          test_bit(EXTENT_BUFFER_STALE, &eb->bflags) &&
 +          !extent_buffer_under_io(eb) &&
 +          test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
 +              atomic_dec(&eb->refs);
 +
 +      /*
 +       * I know this is terrible, but it's temporary until we stop tracking
 +       * the uptodate bits and such for the extent buffers.
 +       */
 +      release_extent_buffer(eb, GFP_ATOMIC);
 +}
 +
 +void free_extent_buffer_stale(struct extent_buffer *eb)
 +{
 +      if (!eb)
                return;
  
 -      WARN_ON(1);
 +      spin_lock(&eb->refs_lock);
 +      set_bit(EXTENT_BUFFER_STALE, &eb->bflags);
 +
 +      if (atomic_read(&eb->refs) == 2 && !extent_buffer_under_io(eb) &&
 +          test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
 +              atomic_dec(&eb->refs);
 +      release_extent_buffer(eb, GFP_NOFS);
  }
  
- int clear_extent_buffer_dirty(struct extent_buffer *eb)
 -void clear_extent_buffer_dirty(struct extent_io_tree *tree,
 -                            struct extent_buffer *eb)
++void clear_extent_buffer_dirty(struct extent_buffer *eb)
  {
        unsigned long i;
        unsigned long num_pages;
                ClearPageError(page);
                unlock_page(page);
        }
 +      WARN_ON(atomic_read(&eb->refs) == 0);
-       return 0;
  }
  
 -int set_extent_buffer_dirty(struct extent_io_tree *tree,
 -                           struct extent_buffer *eb)
 +int set_extent_buffer_dirty(struct extent_buffer *eb)
  {
        unsigned long i;
        unsigned long num_pages;
@@@ -301,12 -286,19 +300,12 @@@ void memmove_extent_buffer(struct exten
                           unsigned long src_offset, unsigned long len);
  void memset_extent_buffer(struct extent_buffer *eb, char c,
                          unsigned long start, unsigned long len);
- int wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits);
- int clear_extent_buffer_dirty(struct extent_buffer *eb);
+ void wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits);
 -void clear_extent_buffer_dirty(struct extent_io_tree *tree,
 -                            struct extent_buffer *eb);
 -int set_extent_buffer_dirty(struct extent_io_tree *tree,
 -                           struct extent_buffer *eb);
 -int set_extent_buffer_uptodate(struct extent_io_tree *tree,
 -                             struct extent_buffer *eb);
 -int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
 -                              struct extent_buffer *eb,
 -                              struct extent_state **cached_state);
 -int extent_buffer_uptodate(struct extent_io_tree *tree,
 -                         struct extent_buffer *eb,
 -                         struct extent_state *cached_state);
++void clear_extent_buffer_dirty(struct extent_buffer *eb);
 +int set_extent_buffer_dirty(struct extent_buffer *eb);
 +int set_extent_buffer_uptodate(struct extent_buffer *eb);
 +int clear_extent_buffer_uptodate(struct extent_buffer *eb);
 +int extent_buffer_uptodate(struct extent_buffer *eb);
  int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
                      unsigned long min_len, char **map,
                      unsigned long *map_start,
Simple merge
@@@ -625,17 -648,22 +648,21 @@@ retry
                }
  
                lock_extent(io_tree, async_extent->start,
-                           async_extent->start + async_extent->ram_size - 1,
-                           GFP_NOFS);
+                           async_extent->start + async_extent->ram_size - 1);
  
                trans = btrfs_join_transaction(root);
-               BUG_ON(IS_ERR(trans));
-               trans->block_rsv = &root->fs_info->delalloc_block_rsv;
-               ret = btrfs_reserve_extent(trans, root,
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+               } else {
+                       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
+                       ret = btrfs_reserve_extent(trans, root,
                                           async_extent->compressed_size,
                                           async_extent->compressed_size,
 -                                         0, alloc_hint,
 -                                         (u64)-1, &ins, 1);
 +                                         0, alloc_hint, &ins, 1);
-               btrfs_end_transaction(trans, root);
+                       if (ret)
+                               btrfs_abort_transaction(trans, root, ret);
+                       btrfs_end_transaction(trans, root);
+               }
  
                if (ret) {
                        int i;
@@@ -837,11 -884,14 +883,14 @@@ static noinline int cow_file_range(stru
                cur_alloc_size = disk_num_bytes;
                ret = btrfs_reserve_extent(trans, root, cur_alloc_size,
                                           root->sectorsize, 0, alloc_hint,
 -                                         (u64)-1, &ins, 1);
 +                                         &ins, 1);
-               BUG_ON(ret);
+               if (ret < 0) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto out_unlock;
+               }
  
                em = alloc_extent_map();
-               BUG_ON(!em);
+               BUG_ON(!em); /* -ENOMEM */
                em->start = start;
                em->orig_start = em->start;
                ram_size = ins.offset;
Simple merge
Simple merge