From patchwork Tue May 11 08:24:00 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Yan, Zheng" X-Patchwork-Id: 98634 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o4B8OPtw020471 for ; Tue, 11 May 2010 08:24:25 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757117Ab0EKIYX (ORCPT ); Tue, 11 May 2010 04:24:23 -0400 Received: from rcsinet10.oracle.com ([148.87.113.121]:26671 "EHLO rcsinet10.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757033Ab0EKIYU (ORCPT ); Tue, 11 May 2010 04:24:20 -0400 Received: from acsinet15.oracle.com (acsinet15.oracle.com [141.146.126.227]) by rcsinet10.oracle.com (Switch-3.4.2/Switch-3.4.1) with ESMTP id o4B8OFnM007732 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 11 May 2010 08:24:17 GMT Received: from acsmt355.oracle.com (acsmt355.oracle.com [141.146.40.155]) by acsinet15.oracle.com (Switch-3.4.2/Switch-3.4.1) with ESMTP id o4B6ZENq031207 for ; Tue, 11 May 2010 08:24:14 GMT Received: from abhmt003.oracle.com by acsmt355.oracle.com with ESMTP id 230478641273566254; Tue, 11 May 2010 01:24:14 -0700 Received: from [192.168.0.100] (/118.112.27.58) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Tue, 11 May 2010 01:24:12 -0700 Message-ID: <4BE91420.5030505@oracle.com> Date: Tue, 11 May 2010 16:24:00 +0800 From: "Yan, Zheng" User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.9) Gecko/20100330 Fedora/3.0.4-1.fc12 Thunderbird/3.0.4 MIME-Version: 1.0 To: linux-btrfs@vger.kernel.org CC: Chris Mason Subject: [PATCH 1/5] btrfs: pass buffer extent to btrfs_free_tree_block X-Auth-Type: Internal IP X-Source-IP: acsinet15.oracle.com [141.146.126.227] X-CT-RefId: str=0001.0A090202.4BE91432.004D:SCFMA922111,ss=1,fgs=0 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Tue, 11 May 2010 08:24:26 +0000 (UTC) diff -urp 1/fs/btrfs/ctree.c 2/fs/btrfs/ctree.c --- 1/fs/btrfs/ctree.c 2010-04-14 14:49:56.342950744 +0800 +++ 2/fs/btrfs/ctree.c 2010-05-11 14:00:04.122357838 +0800 @@ -279,7 +279,8 @@ int btrfs_block_can_be_shared(struct btr static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, - struct extent_buffer *cow) + struct extent_buffer *cow, + int *last_ref) { u64 refs; u64 owner; @@ -365,6 +366,7 @@ static noinline int update_ref_for_cow(s BUG_ON(ret); } clean_tree_block(trans, root, buf); + *last_ref = 1; } return 0; } @@ -392,6 +394,7 @@ static noinline int __btrfs_cow_block(st struct extent_buffer *cow; int level; int unlock_orig = 0; + int last_ref = 0; u64 parent_start; if (*cow_ret == buf) @@ -441,7 +444,7 @@ static noinline int __btrfs_cow_block(st (unsigned long)btrfs_header_fsid(cow), BTRFS_FSID_SIZE); - update_ref_for_cow(trans, root, buf, cow); + update_ref_for_cow(trans, root, buf, cow, &last_ref); if (buf == root->node) { WARN_ON(parent && parent != buf); @@ -456,8 +459,8 @@ static noinline int __btrfs_cow_block(st extent_buffer_get(cow); spin_unlock(&root->node_lock); - btrfs_free_tree_block(trans, root, buf->start, buf->len, - parent_start, root->root_key.objectid, level); + btrfs_free_tree_block(trans, root, buf, parent_start, + last_ref); free_extent_buffer(buf); add_root_to_dirty_list(root); } else { @@ -472,8 +475,8 @@ static noinline int __btrfs_cow_block(st btrfs_set_node_ptr_generation(parent, parent_slot, trans->transid); btrfs_mark_buffer_dirty(parent); - btrfs_free_tree_block(trans, root, buf->start, buf->len, - parent_start, root->root_key.objectid, level); + btrfs_free_tree_block(trans, root, buf, parent_start, + last_ref); } if (unlock_orig) btrfs_tree_unlock(buf); @@ -948,6 +951,22 @@ int btrfs_bin_search(struct extent_buffe return bin_search(eb, key, level, slot); } +static void root_add_used(struct btrfs_root *root, u32 size) +{ + spin_lock(&root->node_lock); + btrfs_set_root_used(&root->root_item, + btrfs_root_used(&root->root_item) + size); + spin_unlock(&root->node_lock); +} + +static void root_sub_used(struct btrfs_root *root, u32 size) +{ + spin_lock(&root->node_lock); + btrfs_set_root_used(&root->root_item, + btrfs_root_used(&root->root_item) - size); + spin_unlock(&root->node_lock); +} + /* given a node and slot number, this reads the blocks it points to. The * extent buffer is returned with a reference taken (but unlocked). * NULL is returned on error. @@ -1018,7 +1037,11 @@ static noinline int balance_level(struct btrfs_tree_lock(child); btrfs_set_lock_blocking(child); ret = btrfs_cow_block(trans, root, child, mid, 0, &child); - BUG_ON(ret); + if (ret) { + btrfs_tree_unlock(child); + free_extent_buffer(child); + goto enospc; + } spin_lock(&root->node_lock); root->node = child; @@ -1033,11 +1056,12 @@ static noinline int balance_level(struct btrfs_tree_unlock(mid); /* once for the path */ free_extent_buffer(mid); - ret = btrfs_free_tree_block(trans, root, mid->start, mid->len, - 0, root->root_key.objectid, level); + + root_sub_used(root, mid->len); + btrfs_free_tree_block(trans, root, mid, 0, 1); /* once for the root ptr */ free_extent_buffer(mid); - return ret; + return 0; } if (btrfs_header_nritems(mid) > BTRFS_NODEPTRS_PER_BLOCK(root) / 4) @@ -1087,23 +1111,16 @@ static noinline int balance_level(struct if (wret < 0 && wret != -ENOSPC) ret = wret; if (btrfs_header_nritems(right) == 0) { - u64 bytenr = right->start; - u32 blocksize = right->len; - clean_tree_block(trans, root, right); btrfs_tree_unlock(right); - free_extent_buffer(right); - right = NULL; wret = del_ptr(trans, root, path, level + 1, pslot + 1); if (wret) ret = wret; - wret = btrfs_free_tree_block(trans, root, - bytenr, blocksize, 0, - root->root_key.objectid, - level); - if (wret) - ret = wret; + root_sub_used(root, right->len); + btrfs_free_tree_block(trans, root, right, 0, 1); + free_extent_buffer(right); + right = NULL; } else { struct btrfs_disk_key right_key; btrfs_node_key(right, &right_key, 0); @@ -1135,21 +1152,15 @@ static noinline int balance_level(struct BUG_ON(wret == 1); } if (btrfs_header_nritems(mid) == 0) { - /* we've managed to empty the middle node, drop it */ - u64 bytenr = mid->start; - u32 blocksize = mid->len; - clean_tree_block(trans, root, mid); btrfs_tree_unlock(mid); - free_extent_buffer(mid); - mid = NULL; wret = del_ptr(trans, root, path, level + 1, pslot); if (wret) ret = wret; - wret = btrfs_free_tree_block(trans, root, bytenr, blocksize, - 0, root->root_key.objectid, level); - if (wret) - ret = wret; + root_sub_used(root, mid->len); + btrfs_free_tree_block(trans, root, mid, 0, 1); + free_extent_buffer(mid); + mid = NULL; } else { /* update the parent key to reflect our changes */ struct btrfs_disk_key mid_key; @@ -1589,7 +1600,7 @@ read_block_for_search(struct btrfs_trans btrfs_release_path(NULL, p); ret = -EAGAIN; - tmp = read_tree_block(root, blocknr, blocksize, gen); + tmp = read_tree_block(root, blocknr, blocksize, 0); if (tmp) { /* * If the read above didn't mark this buffer up to date, @@ -1739,7 +1750,6 @@ again: p->nodes[level + 1], p->slots[level + 1], &b); if (err) { - free_extent_buffer(b); ret = err; goto done; } @@ -1919,6 +1929,7 @@ int btrfs_set_item_key_safe(struct btrfs btrfs_mark_buffer_dirty(eb); if (slot == 0) fixup_low_keys(trans, root, path, &disk_key, 1); + return 0; } @@ -2075,6 +2086,8 @@ static noinline int insert_new_root(stru if (IS_ERR(c)) return PTR_ERR(c); + root_add_used(root, root->nodesize); + memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header)); btrfs_set_header_nritems(c, 1); btrfs_set_header_level(c, level); @@ -2133,6 +2146,7 @@ static int insert_ptr(struct btrfs_trans int nritems; BUG_ON(!path->nodes[level]); + btrfs_assert_tree_locked(path->nodes[level]); lower = path->nodes[level]; nritems = btrfs_header_nritems(lower); BUG_ON(slot > nritems); @@ -2201,6 +2215,8 @@ static noinline int split_node(struct bt if (IS_ERR(split)) return PTR_ERR(split); + root_add_used(root, root->nodesize); + memset_extent_buffer(split, 0, 0, sizeof(struct btrfs_header)); btrfs_set_header_level(split, btrfs_header_level(c)); btrfs_set_header_bytenr(split, split->start); @@ -2414,6 +2430,9 @@ static noinline int __push_leaf_right(st if (left_nritems) btrfs_mark_buffer_dirty(left); + else + clean_tree_block(trans, root, left); + btrfs_mark_buffer_dirty(right); btrfs_item_key(right, &disk_key, 0); @@ -2423,8 +2442,6 @@ static noinline int __push_leaf_right(st /* then fixup the leaf pointer in the path */ if (path->slots[0] >= left_nritems) { path->slots[0] -= left_nritems; - if (btrfs_header_nritems(path->nodes[0]) == 0) - clean_tree_block(trans, root, path->nodes[0]); btrfs_tree_unlock(path->nodes[0]); free_extent_buffer(path->nodes[0]); path->nodes[0] = right; @@ -2657,19 +2674,19 @@ static noinline int __push_leaf_left(str } btrfs_mark_buffer_dirty(left); - if (right_nritems) + if (right_nritems) { btrfs_mark_buffer_dirty(right); - - btrfs_item_key(right, &disk_key, 0); - wret = fixup_low_keys(trans, root, path, &disk_key, 1); - if (wret) - ret = wret; + btrfs_item_key(right, &disk_key, 0); + wret = fixup_low_keys(trans, root, path, &disk_key, 1); + if (wret) + ret = wret; + } else { + clean_tree_block(trans, root, right); + } /* then fixup the leaf pointer in the path */ if (path->slots[0] < push_items) { path->slots[0] += old_left_nritems; - if (btrfs_header_nritems(path->nodes[0]) == 0) - clean_tree_block(trans, root, path->nodes[0]); btrfs_tree_unlock(path->nodes[0]); free_extent_buffer(path->nodes[0]); path->nodes[0] = left; @@ -2931,10 +2948,10 @@ again: right = btrfs_alloc_free_block(trans, root, root->leafsize, 0, root->root_key.objectid, &disk_key, 0, l->start, 0); - if (IS_ERR(right)) { - BUG_ON(1); + if (IS_ERR(right)) return PTR_ERR(right); - } + + root_add_used(root, root->leafsize); memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header)); btrfs_set_header_bytenr(right, right->start); @@ -3053,7 +3070,8 @@ static noinline int setup_leaf_for_split btrfs_set_path_blocking(path); ret = split_leaf(trans, root, &key, path, ins_len, 1); - BUG_ON(ret); + if (ret) + goto err; path->keep_locks = 0; btrfs_unlock_up_safe(path, 1); @@ -3763,6 +3781,7 @@ static int del_ptr(struct btrfs_trans_ha if (wret) ret = wret; } + btrfs_mark_buffer_dirty(parent); return ret; } @@ -3795,9 +3814,10 @@ static noinline int btrfs_del_leaf(struc */ btrfs_unlock_up_safe(path, 0); - ret = btrfs_free_tree_block(trans, root, leaf->start, leaf->len, - 0, root->root_key.objectid, 0); - return ret; + root_sub_used(root, leaf->len); + + btrfs_free_tree_block(trans, root, leaf, 0, 1); + return 0; } /* * delete the item at the leaf level in path. If that empties @@ -3864,6 +3884,8 @@ int btrfs_del_items(struct btrfs_trans_h if (leaf == root->node) { btrfs_set_header_level(leaf, 0); } else { + btrfs_set_path_blocking(path); + clean_tree_block(trans, root, leaf); ret = btrfs_del_leaf(trans, root, path, leaf); BUG_ON(ret); } diff -urp 1/fs/btrfs/ctree.h 2/fs/btrfs/ctree.h --- 1/fs/btrfs/ctree.h 2010-04-14 14:49:56.399956135 +0800 +++ 2/fs/btrfs/ctree.h 2010-05-11 13:57:39.448108941 +0800 @@ -1983,10 +1983,14 @@ struct extent_buffer *btrfs_alloc_free_b u64 parent, u64 root_objectid, struct btrfs_disk_key *key, int level, u64 hint, u64 empty_size); -int btrfs_free_tree_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 bytenr, u32 blocksize, - u64 parent, u64 root_objectid, int level); +void btrfs_free_tree_block(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct extent_buffer *buf, + u64 parent, int last_ref); +void btrfs_free_reserved_tree_block(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + u64 bytenr, u32 blocksize, + struct extent_buffer *buf); struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u32 blocksize, diff -urp 1/fs/btrfs/extent-tree.c 2/fs/btrfs/extent-tree.c --- 1/fs/btrfs/extent-tree.c 2010-04-14 14:49:56.932956992 +0800 +++ 2/fs/btrfs/extent-tree.c 2010-05-11 14:00:54.906106739 +0800 @@ -4066,19 +4066,58 @@ int btrfs_free_extent(struct btrfs_trans return ret; } -int btrfs_free_tree_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 bytenr, u32 blocksize, - u64 parent, u64 root_objectid, int level) -{ - u64 used; - spin_lock(&root->node_lock); - used = btrfs_root_used(&root->root_item) - blocksize; - btrfs_set_root_used(&root->root_item, used); - spin_unlock(&root->node_lock); +void btrfs_free_tree_block(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct extent_buffer *buf, + u64 parent, int last_ref) +{ + struct extent_buffer *orig_buf = buf; + u64 bytenr = buf->start; + u32 blocksize = buf->len; + int level; + int ret; + + if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) { + BUG_ON(!last_ref); + btrfs_free_reserved_tree_block(trans, root, + bytenr, blocksize, buf); + return; + } + + level = btrfs_header_level(buf); + ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent, + root->root_key.objectid, level, 0); + BUG_ON(ret); + + if (orig_buf && orig_buf != buf) + free_extent_buffer(orig_buf); +} - return btrfs_free_extent(trans, root, bytenr, blocksize, - parent, root_objectid, level, 0); +void btrfs_free_reserved_tree_block(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + u64 bytenr, u32 blocksize, + struct extent_buffer *buf) +{ + int ret; + + if (buf) { + bytenr = buf->start; + blocksize = buf->len; + } + + buf = NULL; + ret = pin_down_bytes(trans, root, NULL, bytenr, blocksize, 0, 1, &buf); + + if (buf) { + clean_tree_block(NULL, root, buf); + btrfs_tree_unlock(buf); + free_extent_buffer(buf); + } + + if (ret > 0) { + ret = btrfs_free_reserved_extent(root, bytenr, blocksize); + BUG_ON(ret); + } } static u64 stripe_align(struct btrfs_root *root, u64 val) diff -urp 1/fs/btrfs/tree-log.c 2/fs/btrfs/tree-log.c --- 1/fs/btrfs/tree-log.c 2010-04-14 14:49:58.978946890 +0800 +++ 2/fs/btrfs/tree-log.c 2010-05-11 13:27:58.658108016 +0800 @@ -1671,7 +1671,6 @@ static noinline int walk_down_log_tree(s struct extent_buffer *cur; struct extent_buffer *parent; u32 blocksize; - int ret = 0; WARN_ON(*level < 0); WARN_ON(*level >= BTRFS_MAX_LEVEL); @@ -1713,9 +1712,8 @@ static noinline int walk_down_log_tree(s WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID); - ret = btrfs_free_reserved_extent(root, - bytenr, blocksize); - BUG_ON(ret); + btrfs_free_reserved_tree_block(trans, root, + 0, 0, next); } free_extent_buffer(next); continue; @@ -1756,8 +1754,7 @@ static noinline int walk_down_log_tree(s btrfs_tree_unlock(next); WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID); - ret = btrfs_free_reserved_extent(root, bytenr, blocksize); - BUG_ON(ret); + btrfs_free_reserved_tree_block(trans, root, 0, 0, next); } free_extent_buffer(path->nodes[*level]); path->nodes[*level] = NULL; @@ -1776,7 +1773,6 @@ static noinline int walk_up_log_tree(str u64 root_gen; int i; int slot; - int ret; for (i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { slot = path->slots[i]; @@ -1810,10 +1806,8 @@ static noinline int walk_up_log_tree(str btrfs_tree_unlock(next); WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID); - ret = btrfs_free_reserved_extent(root, - path->nodes[*level]->start, - path->nodes[*level]->len); - BUG_ON(ret); + btrfs_free_reserved_tree_block(trans, root, + 0, 0, path->nodes[*level]); } free_extent_buffer(path->nodes[*level]); path->nodes[*level] = NULL; @@ -1878,9 +1872,7 @@ static int walk_log_tree(struct btrfs_tr WARN_ON(log->root_key.objectid != BTRFS_TREE_LOG_OBJECTID); - ret = btrfs_free_reserved_extent(log, next->start, - next->len); - BUG_ON(ret); + btrfs_free_reserved_tree_block(trans, log, 0, 0, next); } }