summaryrefslogtreecommitdiff
path: root/fs/btrfs
diff options
context:
space:
mode:
authorYan Zheng <zheng.yan@oracle.com>2008-10-09 19:46:19 +0400
committerChris Mason <chris.mason@oracle.com>2008-10-09 19:46:19 +0400
commit5b84e8d6eef82fcf7b1b16d92e29375b85b6549a (patch)
treed9ab309bc09f8a615aab2c0728272fa773beacf7 /fs/btrfs
parent3bb1a1bc42f2ae9582c28adf620484efcd4da38d (diff)
downloadlinux-5b84e8d6eef82fcf7b1b16d92e29375b85b6549a.tar.xz
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/btrfs')
-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,
}
ret = btrfs_add_leaf_ref(root, ref, shared);
+ if (ret == -EEXIST && shared) {
+ struct btrfs_leaf_ref *old;
+ old = btrfs_lookup_leaf_ref(root, ref->bytenr);
+ BUG_ON(!old);
+ btrfs_remove_leaf_ref(root, old);
+ btrfs_free_leaf_ref(root, old);
+ ret = btrfs_add_leaf_ref(root, ref, shared);
+ }
WARN_ON(ret);
btrfs_free_leaf_ref(root, ref);
}
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 @@
#include "xattr.h"
#include "compat.h"
#include "tree-log.h"
+#include "ref-cache.h"
struct btrfs_iget_args {
u64 ino;
@@ -1416,6 +1417,9 @@ static noinline int drop_csum_leaves(struct btrfs_trans_handle *trans,
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;
@@ -1509,15 +1513,31 @@ next_node:
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,
- btrfs_node_blockptr(path->nodes[1],
- path->slots[1]));
+ 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;
+
+ 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);