aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorYan Zheng <zheng.yan@oracle.com>2008-10-09 11:46:19 -0400
committerChris Mason <chris.mason@oracle.com>2008-10-09 11:46:19 -0400
commit5b84e8d6eef82fcf7b1b16d92e29375b85b6549a (patch)
treed9ab309bc09f8a615aab2c0728272fa773beacf7 /fs
parent3bb1a1bc42f2ae9582c28adf620484efcd4da38d (diff)
Btrfs: Fix leaf reference cache miss
Due to the optimization for truncate, tree leaves only containing checksum items can be deleted without being COW'ed first. This causes reference cache misses. The way to fix the miss is create cache entries for tree leaves only contain checksum. This patch also fixes a -EEXIST issue in shared reference cache. Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/extent-tree.c8
-rw-r--r--fs/btrfs/inode.c26
2 files changed, 31 insertions, 3 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index ab36769c356c..280ac1aa9b6d 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1151,6 +1151,14 @@ int btrfs_cache_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
1151 } 1151 }
1152 1152
1153 ret = btrfs_add_leaf_ref(root, ref, shared); 1153 ret = btrfs_add_leaf_ref(root, ref, shared);
1154 if (ret == -EEXIST && shared) {
1155 struct btrfs_leaf_ref *old;
1156 old = btrfs_lookup_leaf_ref(root, ref->bytenr);
1157 BUG_ON(!old);
1158 btrfs_remove_leaf_ref(root, old);
1159 btrfs_free_leaf_ref(root, old);
1160 ret = btrfs_add_leaf_ref(root, ref, shared);
1161 }
1154 WARN_ON(ret); 1162 WARN_ON(ret);
1155 btrfs_free_leaf_ref(root, ref); 1163 btrfs_free_leaf_ref(root, ref);
1156 } 1164 }
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 3ab147dc3c05..11bfe131fde6 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -48,6 +48,7 @@
48#include "xattr.h" 48#include "xattr.h"
49#include "compat.h" 49#include "compat.h"
50#include "tree-log.h" 50#include "tree-log.h"
51#include "ref-cache.h"
51 52
52struct btrfs_iget_args { 53struct btrfs_iget_args {
53 u64 ino; 54 u64 ino;
@@ -1416,6 +1417,9 @@ static noinline int drop_csum_leaves(struct btrfs_trans_handle *trans,
1416 int nritems; 1417 int nritems;
1417 struct btrfs_key found_key; 1418 struct btrfs_key found_key;
1418 struct btrfs_key other_key; 1419 struct btrfs_key other_key;
1420 struct btrfs_leaf_ref *ref;
1421 u64 leaf_gen;
1422 u64 leaf_start;
1419 1423
1420 path->lowest_level = 1; 1424 path->lowest_level = 1;
1421 key.objectid = inode->i_ino; 1425 key.objectid = inode->i_ino;
@@ -1509,15 +1513,31 @@ next_node:
1509 if (other_key.objectid != inode->i_ino || other_key.type != key.type) 1513 if (other_key.objectid != inode->i_ino || other_key.type != key.type)
1510 goto out; 1514 goto out;
1511 1515
1516 leaf_start = btrfs_node_blockptr(path->nodes[1], path->slots[1]);
1517 leaf_gen = btrfs_node_ptr_generation(path->nodes[1], path->slots[1]);
1512 /* 1518 /*
1513 * it is safe to delete this leaf, it contains only 1519 * it is safe to delete this leaf, it contains only
1514 * csum items from this inode at an offset >= new_size 1520 * csum items from this inode at an offset >= new_size
1515 */ 1521 */
1516 ret = btrfs_del_leaf(trans, root, path, 1522 ret = btrfs_del_leaf(trans, root, path, leaf_start);
1517 btrfs_node_blockptr(path->nodes[1],
1518 path->slots[1]));
1519 BUG_ON(ret); 1523 BUG_ON(ret);
1520 1524
1525 if (root->ref_cows && leaf_gen < trans->transid) {
1526 ref = btrfs_alloc_leaf_ref(root, 0);
1527 if (ref) {
1528 ref->root_gen = root->root_key.offset;
1529 ref->bytenr = leaf_start;
1530 ref->owner = 0;
1531 ref->generation = leaf_gen;
1532 ref->nritems = 0;
1533
1534 ret = btrfs_add_leaf_ref(root, ref, 0);
1535 WARN_ON(ret);
1536 btrfs_free_leaf_ref(root, ref);
1537 } else {
1538 WARN_ON(1);
1539 }
1540 }
1521next_key: 1541next_key:
1522 btrfs_release_path(root, path); 1542 btrfs_release_path(root, path);
1523 1543