Skip to content

Commit

Permalink
Btrfs: Add a leaf reference cache
Browse files Browse the repository at this point in the history
Much of the IO done while dropping snapshots is done looking up
leaves in the filesystem trees to see if they point to any extents and
to drop the references on any extents found.

This creates a cache so that IO isn't required.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
Yan Zheng authored and Chris Mason committed Sep 25, 2008
1 parent 3a115f5 commit 31153d8
Show file tree
Hide file tree
Showing 8 changed files with 476 additions and 33 deletions.
3 changes: 2 additions & 1 deletion fs/btrfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
hash.o file-item.o inode-item.o inode-map.o disk-io.o \
transaction.o bit-radix.o inode.o file.o tree-defrag.o \
extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
ref-cache.o

btrfs-$(CONFIG_FS_POSIX_ACL) += acl.o
else
Expand Down
4 changes: 2 additions & 2 deletions fs/btrfs/ctree.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);

WARN_ON(btrfs_header_generation(buf) > trans->transid);
ret = btrfs_inc_ref(trans, new_root, buf);
ret = btrfs_inc_ref(trans, new_root, buf, 0);
kfree(new_root);

if (ret)
Expand Down Expand Up @@ -232,7 +232,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
WARN_ON(btrfs_header_generation(buf) > trans->transid);
if (btrfs_header_generation(buf) != trans->transid) {
different_trans = 1;
ret = btrfs_inc_ref(trans, root, buf);
ret = btrfs_inc_ref(trans, root, buf, 1);
if (ret)
return ret;
} else {
Expand Down
8 changes: 7 additions & 1 deletion fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,10 @@ struct btrfs_fs_info {
u64 last_alloc;
u64 last_data_alloc;

spinlock_t ref_cache_lock;
u64 total_ref_cache_size;
u64 running_ref_cache_size;

u64 avail_data_alloc_bits;
u64 avail_metadata_alloc_bits;
u64 avail_system_alloc_bits;
Expand All @@ -613,6 +617,8 @@ struct btrfs_root {
spinlock_t node_lock;

struct extent_buffer *commit_root;
struct btrfs_leaf_ref_tree *ref_tree;

struct btrfs_root_item root_item;
struct btrfs_key root_key;
struct btrfs_fs_info *fs_info;
Expand Down Expand Up @@ -1430,7 +1436,7 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
u64 search_end, struct btrfs_key *ins,
u64 data);
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct extent_buffer *buf);
struct extent_buffer *buf, int cache_ref);
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
*root, u64 bytenr, u64 num_bytes,
u64 root_objectid, u64 ref_generation,
Expand Down
14 changes: 14 additions & 0 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
root->node = NULL;
root->inode = NULL;
root->commit_root = NULL;
root->ref_tree = NULL;
root->sectorsize = sectorsize;
root->nodesize = nodesize;
root->leafsize = leafsize;
Expand Down Expand Up @@ -1165,12 +1166,19 @@ static int transaction_kthread(void *arg)
vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE);
mutex_lock(&root->fs_info->transaction_kthread_mutex);

printk("btrfs: total reference cache size %Lu\n",
root->fs_info->total_ref_cache_size);

mutex_lock(&root->fs_info->trans_mutex);
cur = root->fs_info->running_transaction;
if (!cur) {
mutex_unlock(&root->fs_info->trans_mutex);
goto sleep;
}

printk("btrfs: running reference cache size %Lu\n",
root->fs_info->running_ref_cache_size);

now = get_seconds();
if (now < cur->start_time || now - cur->start_time < 30) {
mutex_unlock(&root->fs_info->trans_mutex);
Expand Down Expand Up @@ -1233,6 +1241,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
spin_lock_init(&fs_info->hash_lock);
spin_lock_init(&fs_info->delalloc_lock);
spin_lock_init(&fs_info->new_trans_lock);
spin_lock_init(&fs_info->ref_cache_lock);

init_completion(&fs_info->kobj_unregister);
fs_info->tree_root = tree_root;
Expand Down Expand Up @@ -1699,6 +1708,11 @@ int close_ctree(struct btrfs_root *root)
printk("btrfs: at unmount delalloc count %Lu\n",
fs_info->delalloc_bytes);
}
if (fs_info->total_ref_cache_size) {
printk("btrfs: at umount reference cache size %Lu\n",
fs_info->total_ref_cache_size);
}

if (fs_info->extent_root->node)
free_extent_buffer(fs_info->extent_root->node);

Expand Down
115 changes: 104 additions & 11 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "transaction.h"
#include "volumes.h"
#include "locking.h"
#include "ref-cache.h"

#define BLOCK_GROUP_DATA EXTENT_WRITEBACK
#define BLOCK_GROUP_METADATA EXTENT_UPTODATE
Expand Down Expand Up @@ -927,7 +928,7 @@ u32 btrfs_count_snapshots_in_path(struct btrfs_root *root,
}

int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct extent_buffer *buf)
struct extent_buffer *buf, int cache_ref)
{
u64 bytenr;
u32 nritems;
Expand All @@ -937,6 +938,7 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
int level;
int ret;
int faili;
int nr_file_extents = 0;

if (!root->ref_cows)
return 0;
Expand All @@ -959,6 +961,9 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
if (disk_bytenr == 0)
continue;

if (buf != root->commit_root)
nr_file_extents++;

mutex_lock(&root->fs_info->alloc_mutex);
ret = __btrfs_inc_extent_ref(trans, root, disk_bytenr,
btrfs_file_extent_disk_num_bytes(buf, fi),
Expand Down Expand Up @@ -988,6 +993,53 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
}
}
}
/* cache orignal leaf block's references */
if (level == 0 && cache_ref && buf != root->commit_root) {
struct btrfs_leaf_ref *ref;
struct btrfs_extent_info *info;

ref = btrfs_alloc_leaf_ref(nr_file_extents);
if (!ref) {
WARN_ON(1);
goto out;
}

btrfs_item_key_to_cpu(buf, &ref->key, 0);

ref->bytenr = buf->start;
ref->owner = btrfs_header_owner(buf);
ref->generation = btrfs_header_generation(buf);
ref->nritems = nr_file_extents;
info = ref->extents;

for (i = 0; nr_file_extents > 0 && i < nritems; i++) {
u64 disk_bytenr;
btrfs_item_key_to_cpu(buf, &key, i);
if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY)
continue;
fi = btrfs_item_ptr(buf, i,
struct btrfs_file_extent_item);
if (btrfs_file_extent_type(buf, fi) ==
BTRFS_FILE_EXTENT_INLINE)
continue;
disk_bytenr = btrfs_file_extent_disk_bytenr(buf, fi);
if (disk_bytenr == 0)
continue;

info->bytenr = disk_bytenr;
info->num_bytes =
btrfs_file_extent_disk_num_bytes(buf, fi);
info->objectid = key.objectid;
info->offset = key.offset;
info++;
}

BUG_ON(!root->ref_tree);
ret = btrfs_add_leaf_ref(root, ref);
WARN_ON(ret);
btrfs_free_leaf_ref(ref);
}
out:
return 0;
fail:
WARN_ON(1);
Expand Down Expand Up @@ -2215,9 +2267,9 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
return buf;
}

static int noinline drop_leaf_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *leaf)
static int noinline drop_leaf_ref_no_cache(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *leaf)
{
u64 leaf_owner;
u64 leaf_generation;
Expand Down Expand Up @@ -2266,6 +2318,30 @@ static int noinline drop_leaf_ref(struct btrfs_trans_handle *trans,
return 0;
}

static int noinline drop_leaf_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_leaf_ref *ref)
{
int i;
int ret;
struct btrfs_extent_info *info = ref->extents;

mutex_unlock(&root->fs_info->alloc_mutex);
for (i = 0; i < ref->nritems; i++) {
mutex_lock(&root->fs_info->alloc_mutex);
ret = __btrfs_free_extent(trans, root,
info->bytenr, info->num_bytes,
ref->owner, ref->generation,
info->objectid, info->offset, 0);
mutex_unlock(&root->fs_info->alloc_mutex);
BUG_ON(ret);
info++;
}
mutex_lock(&root->fs_info->alloc_mutex);

return 0;
}

static void noinline reada_walk_down(struct btrfs_root *root,
struct extent_buffer *node,
int slot)
Expand Down Expand Up @@ -2341,6 +2417,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
struct extent_buffer *next;
struct extent_buffer *cur;
struct extent_buffer *parent;
struct btrfs_leaf_ref *ref;
u32 blocksize;
int ret;
u32 refs;
Expand Down Expand Up @@ -2370,7 +2447,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
btrfs_header_nritems(cur))
break;
if (*level == 0) {
ret = drop_leaf_ref(trans, root, cur);
ret = drop_leaf_ref_no_cache(trans, root, cur);
BUG_ON(ret);
break;
}
Expand All @@ -2391,14 +2468,28 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
BUG_ON(ret);
continue;
}

if (*level == 1) {
struct btrfs_key key;
btrfs_node_key_to_cpu(cur, &key, path->slots[*level]);
ref = btrfs_lookup_leaf_ref(root, &key);
if (ref) {
ret = drop_leaf_ref(trans, root, ref);
BUG_ON(ret);
btrfs_remove_leaf_ref(root, ref);
btrfs_free_leaf_ref(ref);
*level = 0;
break;
}
}

next = btrfs_find_tree_block(root, bytenr, blocksize);
if (!next || !btrfs_buffer_uptodate(next, ptr_gen)) {
free_extent_buffer(next);
mutex_unlock(&root->fs_info->alloc_mutex);

if (path->slots[*level] == 0)
reada_walk_down(root, cur, path->slots[*level]);

next = read_tree_block(root, bytenr, blocksize,
ptr_gen);
cond_resched();
Expand Down Expand Up @@ -2435,17 +2526,19 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
WARN_ON(*level >= BTRFS_MAX_LEVEL);

if (path->nodes[*level] == root->node) {
root_owner = root->root_key.objectid;
parent = path->nodes[*level];
bytenr = path->nodes[*level]->start;
} else {
parent = path->nodes[*level + 1];
root_owner = btrfs_header_owner(parent);
bytenr = btrfs_node_blockptr(parent, path->slots[*level + 1]);
}

blocksize = btrfs_level_size(root, *level);
root_owner = btrfs_header_owner(parent);
root_gen = btrfs_header_generation(parent);
ret = __btrfs_free_extent(trans, root, path->nodes[*level]->start,
path->nodes[*level]->len,
root_owner, root_gen, 0, 0, 1);

ret = __btrfs_free_extent(trans, root, bytenr, blocksize,
root_owner, root_gen, 0, 0, 1);
free_extent_buffer(path->nodes[*level]);
path->nodes[*level] = NULL;
*level += 1;
Expand Down
Loading

0 comments on commit 31153d8

Please sign in to comment.