From: Chris Mason Date: Thu, 29 Mar 2012 00:31:37 +0000 (-0400) Subject: Merge branch 'error-handling' into for-linus X-Git-Tag: firefly_0821_release~3680^2~2940^2~51 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=1d4284bd6e8d7dd1d5521a6747bdb6dc1caf0225;p=firefly-linux-kernel-4.4.55.git Merge branch 'error-handling' into for-linus 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 --- 1d4284bd6e8d7dd1d5521a6747bdb6dc1caf0225 diff --cc fs/btrfs/ctree.c index 270655da11d1,e697afd18159..e801f226d7e0 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.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; @@@ -1064,12 -1067,10 +1080,10 @@@ 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 diff --cc fs/btrfs/disk-io.c index 6107b6958413,fe087847c8e7..7b55eee15a51 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@@ -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); @@@ -1098,15 -1155,15 +1117,14 @@@ /* 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; diff --cc fs/btrfs/extent-tree.c index 1b831ac4c079,4b3f1eedced0..8b304e3537c4 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@@ -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; diff --cc fs/btrfs/extent_io.c index 49a368593a16,4c3ce7a0a7a4..0c3ec003f273 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@@ -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; @@@ -4267,11 -3871,10 +4309,10 @@@ 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; diff --cc fs/btrfs/extent_io.h index 38c1af7092f3,3a171c259276..faf10eb57f75 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@@ -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, diff --cc fs/btrfs/inode.c index 341a8670165f,d6420cca9c8d..eb6aec7bbacb --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@@ -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;