initial version of reference cache
Subsystems (2)
PATCH 1/1 initial version of reference cache
Hello,
This is the initial version of leaf reference cache. The cache stores leaf node's extent references in memory, this can improve the performance of snapshot dropping. Outlines of this patch are (1) allocate struct dirty_root when starting transaction (2) put reference cache in struct dirty_root (3) cache extent references when tree leaves are cow'ed (4) when dropping snapshot, use cached references directly to avoid reading tree leaf.
I only can access a notebook currenly, so benchmarking isn't enough. I appreciate any help and comment.
Regards
YZ
---
Makefile +2 -1
@@ -6,7 +6,8 @@ btrfs-y := super.o ctree.o extent-tree.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
ctree.c +2 -2
@@ -165,7 +165,7 @@ int btrfs_copy_root(struct btrfs_trans_hbtrfs_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)
@@ -232,7 +232,7 @@ int __btrfs_cow_block(struct btrfs_transWARN_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 {
ctree.h +7 -1
@@ -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;
@@ -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;
@@ -1430,7 +1436,7 @@ int btrfs_reserve_extent(struct btrfs_tr 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,
disk-io.c +14 -0
@@ -716,6 +716,7 @@ static int __setup_root(u32 nodesize, u3 root->node =NULL ; root->inode =NULL ; root->commit_root =NULL ; + root->ref_tree =NULL ; root->sectorsize = sectorsize; root->nodesize = nodesize; root->leafsize = leafsize;
@@ -1165,12 +1166,19 @@ static int transaction_kthread(void *argvfs_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);
@@ -1233,6 +1241,7 @@ struct btrfs_root *open_ctree(struct supspin_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;
@@ -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);
extent-tree.c +106 -12
188 lines not on this page · raw message
transaction.c +50 -18
147 lines not on this page · raw message
Quoted 6 lines · Yan Zheng
Hello,
This is the initial version of leaf reference cache. The cache stores leaf node's extent references in memory, this can improve the performance of snapshot dropping. Outlines of this patch are (1) allocate struct
dirty_rootwhen starting transaction (2) put reference cache in structdirty_root(3) cache extent references when tree leaves are cow'ed (4) when dropping snapshot, use cached references directly to avoid reading tree leaf.I only can access a notebook currenly, so benchmarking isn't enough. I appreciate any help and comment.
I have modified this locally to always cache leaves, even when they don't have file extents in them. That way, walk_down_tree will find the cache and won't have to read the leaf (that doesn't have any extents).
So far, it is working very well. I did a run with fs_mark to create 58 million files and had very steady numbers. The unmount took 4 seconds. It used to take over an hour.
One question, why not use the block number (byte number) as the key to the rbtree instead of the key?
-chris
2008/7/26 Chris Mason <[email protected]>:
Quoted 11 lines
I have modified this locally to always cache leaves, even when they don't have file extents in them. That way,
walk_down_treewill find the cache and won't have to read the leaf (that doesn't have any extents).So far, it is working very well. I did a run with
fs_markto create 58 million files and had very steady numbers. The unmount took 4 seconds. It used to take over an hour.One question, why not use the block number (byte number) as the key to the rbtree instead of the key?
When dropping old snapshots, tree leaves are processed in ascending order of btrfs_key. After a given tree leaf is processed, we remove the corresponding cache entry and update tree->last to point to next entry in the tree. Therefore btrfs_lookup_leaf_ref can find the wanted entry in tree->last in most cases.
Regards
YZ
Yan and I are hammering this out a little, I've attached my current patches.
I was seeing cache misses after long stress runs, which I think is coming from references on the higher levels of the tree making us skip some leaves while dropping the transaction that added them.
My new version using a single cache per root, and should avoid these misses.
extent-tree.c +2 -3
@@ -994,7 +994,7 @@ int btrfs_inc_ref(struct btrfs_trans_han } }/* cache orignal leaf block's references */ -if (cache_ref && nr_file_extents >0 ) { +if (level ==0 && cache_ref && buf != root->commit_root) {struct btrfs_leaf_ref *ref;struct btrfs_extent_info *info;
@@ -1012,7 +1012,7 @@ int btrfs_inc_ref(struct btrfs_trans_han ref->nritems = nr_file_extents; info = ref->extents; -for (i =0 ; i < nritems; i++) { +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 )
@@ -2490,7 +2490,6 @@ static int noinline walk_down_tree(strucif (path->slots[*level] ==0 )reada_walk_down (root, cur, path->slots[*level]); - next =read_tree_block (root, bytenr, blocksize, ptr_gen);cond_resched ();
ref-cache.c +33 -2
@@ -16,6 +16,7 @@* Boston, MA 021110-1307, USA. */ +#include <linux/sched.h> #include "ctree.h" #include "ref-cache.h" #include "transaction.h"
@@ -110,6 +111,34 @@ static struct rb_node *tree_search(strucreturn NULL ; } +int btrfs_remove_leaf_refs (struct btrfs_root *root) +{ +struct rb_node *rb; +struct btrfs_leaf_ref *ref =NULL ; +struct btrfs_leaf_ref_tree *tree = root->ref_tree; + +if (!tree) +return 0 ; + +spin_lock (&tree->lock); +while (!btrfs_leaf_ref_tree_empty (tree)) { + tree->last =NULL ; + rb =rb_first (&tree->root); + ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node); +rb_erase (&ref->rb_node, &tree->root); + ref->in_tree =0 ; + +spin_unlock (&tree->lock); + +btrfs_free_leaf_ref (ref); + +cond_resched (); +spin_lock (&tree->lock); + } +spin_unlock (&tree->lock); +return 0 ; +} +struct btrfs_leaf_ref *btrfs_lookup_leaf_ref (struct btrfs_root *root,struct btrfs_key *key) {
@@ -170,8 +199,6 @@ int btrfs_remove_leaf_ref(struct btrfs_rBUG_ON (!ref->in_tree);spin_lock (&tree->lock); -rb_erase (&ref->rb_node, &tree->root); - ref->in_tree =0 ;spin_lock (&root->fs_info->ref_cache_lock); root->fs_info->total_ref_cache_size -= size;
@@ -187,6 +214,10 @@ int btrfs_remove_leaf_ref(struct btrfs_r }else tree->last =NULL ; } + +rb_erase (&ref->rb_node, &tree->root); + ref->in_tree =0 ; +spin_unlock (&tree->lock);btrfs_free_leaf_ref (ref);
ref-cache.h +1 -0
@@ -68,4 +68,5 @@ struct btrfs_leaf_ref *btrfs_lookup_leafstruct btrfs_leaf_ref *btrfs_lookup_leaf_ref (struct btrfs_root *root,struct btrfs_key *key);int btrfs_add_leaf_ref (struct btrfs_root *root,struct btrfs_leaf_ref *ref); +int btrfs_remove_leaf_refs (struct btrfs_root *root);int btrfs_remove_leaf_ref (struct btrfs_root *root,struct btrfs_leaf_ref *ref);
transaction.c +2 -3
@@ -539,9 +539,8 @@ static noinline int drop_dirty_roots(str ret =btrfs_end_transaction (trans, tree_root);BUG_ON (ret); -if (dirty->root->ref_tree) -WARN_ON (!btrfs_leaf_ref_tree_empty (dirty->root->ref_tree)); - +btrfs_remove_leaf_refs (dirty->root); +free_extent_buffer (dirty->root->node);kfree (dirty->root);kfree (dirty);
ctree.h +9 -1
@@ -594,7 +594,6 @@ struct btrfs_fs_info {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;
@@ -606,10 +605,17 @@ struct btrfs_fs_info {void *bdev_holder; }; +struct btrfs_leaf_ref_tree { +struct rb_root root; +struct btrfs_leaf_ref *last; +spinlock_t lock; +}; +/* * in ram representation of the tree. extent_root is used for all allocations * and for the extent tree extent_root root. */ +struct dirty_root ;struct btrfs_root {struct extent_buffer *node;
@@ -618,6 +624,8 @@ struct btrfs_root {struct extent_buffer *commit_root;struct btrfs_leaf_ref_tree *ref_tree; +struct btrfs_leaf_ref_tree ref_tree_struct; +struct dirty_root *dirty_root;struct btrfs_root_item root_item;struct btrfs_key root_key;
disk-io.c +5 -3
@@ -40,6 +40,7 @@#include "print-tree.h" #include "async-thread.h" #include "locking.h" +#include "ref-cache.h" #if 0 static int check_tree_block (struct btrfs_root *root,struct extent_buffer *buf)
@@ -737,6 +738,10 @@ static int __setup_root(u32 nodesize, u3spin_lock_init (&root->node_lock);spin_lock_init (&root->orphan_lock);mutex_init (&root->objectid_mutex); + +btrfs_leaf_ref_tree_init (&root->ref_tree_struct); + root->ref_tree = &root->ref_tree_struct; +memset (&root->root_key,0 ,sizeof (root->root_key));memset (&root->root_item,0 ,sizeof (root->root_item));memset (&root->defrag_progress,0 ,sizeof (root->defrag_progress));
@@ -1176,9 +1181,6 @@ static int transaction_kthread(void *arg 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);
extent-tree.c +3 -3
@@ -2468,11 +2468,11 @@ static int noinline walk_down_tree(strucBUG_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); + ref =btrfs_lookup_leaf_ref (root, ptr_gen, &key);if (ref) { ret =drop_leaf_ref (trans, root, ref);BUG_ON (ret);
@@ -2481,8 +2481,8 @@ static int noinline walk_down_tree(struc *level =0 ;break ; } +printk ("extent cache miss bytenr %Lu gen %Lu\n" , bytenr, ptr_gen); } - next =btrfs_find_tree_block (root, bytenr, blocksize);if (!next || !btrfs_buffer_uptodate (next, ptr_gen)) {free_extent_buffer (next);
ref-cache.c +18 -14
@@ -44,8 +44,13 @@ void btrfs_free_leaf_ref(struct btrfs_le } } -static int comp_keys (struct btrfs_key *k1,struct btrfs_key *k2) +static int comp_keys (u64 gen1,u64 gen2,struct btrfs_key *k1, +struct btrfs_key *k2) { +if (gen1 > gen2) +return 1 ; +if (gen1 < gen2) +return -1 ;if (k1->objectid > k2->objectid)return 1 ;if (k1->objectid < k2->objectid)
@@ -61,7 +66,8 @@ static int comp_keys(struct btrfs_key *kreturn 0 ; } -static struct rb_node *tree_insert (struct rb_root *root,struct btrfs_key *key, +static struct rb_node *tree_insert (struct rb_root *root,u64 gen, +struct btrfs_key *key,struct rb_node *node) {struct rb_node ** p = &root->rb_node;
@@ -74,7 +80,7 @@ static struct rb_node *tree_insert(struc entry = rb_entry(parent, struct btrfs_leaf_ref, rb_node);WARN_ON (!entry->in_tree); - ret =comp_keys (key, &entry->key); + ret =comp_keys (gen, entry->generation, key, &entry->key);if (ret <0 ) p = &(*p)->rb_left;else if (ret >0 )
@@ -90,7 +96,8 @@ static struct rb_node *tree_insert(strucreturn NULL ; } -static struct rb_node *tree_search (struct rb_root *root,struct btrfs_key *key) +static struct rb_node *tree_search (struct rb_root *root,u64 gen, +struct btrfs_key *key) {struct rb_node * n = root->rb_node;struct btrfs_leaf_ref *entry;
@@ -100,7 +107,7 @@ static struct rb_node *tree_search(struc entry = rb_entry(n, struct btrfs_leaf_ref, rb_node);WARN_ON (!entry->in_tree); - ret =comp_keys (key, &entry->key); + ret =comp_keys (gen, entry->generation, key, &entry->key);if (ret <0 ) n = n->rb_left;else if (ret >0 )
@@ -140,6 +147,7 @@ int btrfs_remove_leaf_refs(struct btrfs_ }struct btrfs_leaf_ref *btrfs_lookup_leaf_ref (struct btrfs_root *root, +u64 generation,struct btrfs_key *key) {struct rb_node *rb;
@@ -150,10 +158,11 @@ struct btrfs_leaf_ref *btrfs_lookup_leafreturn NULL ;spin_lock (&tree->lock); -if (tree->last &&comp_keys (key, &tree->last->key) ==0 ) { +if (tree->last &&comp_keys (generation, tree->last->generation, + key, &tree->last->key) ==0 ) { ref = tree->last; }else { - rb =tree_search (&tree->root, key); + rb =tree_search (&tree->root, generation, key);if (rb) { ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node); tree->last = ref;
@@ -171,17 +180,15 @@ int btrfs_add_leaf_ref(struct btrfs_rootstruct rb_node *rb;size_t size =btrfs_leaf_ref_size (ref->nritems);struct btrfs_leaf_ref_tree *tree = root->ref_tree; -struct btrfs_transaction *trans = root->fs_info->running_transaction;spin_lock (&tree->lock); - rb =tree_insert (&tree->root, &ref->key, &ref->rb_node); + rb =tree_insert (&tree->root, ref->generation, &ref->key, + &ref->rb_node);if (rb) { ret = -EEXIST ; }else {spin_lock (&root->fs_info->ref_cache_lock); root->fs_info->total_ref_cache_size += size; -if (trans && tree->generation == trans->transid) - root->fs_info->running_ref_cache_size += size;spin_unlock (&root->fs_info->ref_cache_lock); tree->last = ref;
@@ -195,15 +202,12 @@ int btrfs_remove_leaf_ref(struct btrfs_r {size_t size =btrfs_leaf_ref_size (ref->nritems);struct btrfs_leaf_ref_tree *tree = root->ref_tree; -struct btrfs_transaction *trans = root->fs_info->running_transaction;BUG_ON (!ref->in_tree);spin_lock (&tree->lock);spin_lock (&root->fs_info->ref_cache_lock); root->fs_info->total_ref_cache_size -= size; -if (trans && tree->generation == trans->transid) - root->fs_info->running_ref_cache_size -= size;spin_unlock (&root->fs_info->ref_cache_lock);if (tree->last == ref) {
ref-cache.h +5 -9
@@ -15,6 +15,8 @@* Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ +#ifndef __REFCACHE__ +#define __REFCACHE__ struct btrfs_extent_info { u64 bytenr;
@@ -36,13 +38,6 @@ struct btrfs_leaf_ref {struct btrfs_extent_info extents[]; }; -struct btrfs_leaf_ref_tree { -struct rb_root root; -struct btrfs_leaf_ref *last; -u64 generation; -spinlock_t lock; -}; -static inline size_t btrfs_leaf_ref_size (int nr_extents) { return sizeof(struct btrfs_leaf_ref) +
@@ -53,7 +48,6 @@ static inline void btrfs_leaf_ref_tree_i { tree->root.rb_node =NULL ; tree->last =NULL ; - tree->generation =0 ;spin_lock_init (&tree->lock); }
@@ -66,7 +60,9 @@ struct btrfs_leaf_ref *btrfs_alloc_leaf_struct btrfs_leaf_ref *btrfs_alloc_leaf_ref (int nr_extents);void btrfs_free_leaf_ref (struct btrfs_leaf_ref *ref);struct btrfs_leaf_ref *btrfs_lookup_leaf_ref (struct btrfs_root *root, -struct btrfs_key *key); +u64 gen,struct btrfs_key *key);int btrfs_add_leaf_ref (struct btrfs_root *root,struct btrfs_leaf_ref *ref);int btrfs_remove_leaf_refs (struct btrfs_root *root);int btrfs_remove_leaf_ref (struct btrfs_root *root,struct btrfs_leaf_ref *ref); + +#endif
transaction.c +6 -18
@@ -36,7 +36,6 @@ struct dirty_root {struct list_head list;struct btrfs_root *root;struct btrfs_root *latest_root; -struct btrfs_leaf_ref_tree ref_tree; }; static noinline void put_transaction(struct btrfs_transaction *transaction)
@@ -108,13 +107,13 @@ static noinline int record_root_in_trans dirty->latest_root = root;INIT_LIST_HEAD (&dirty->list); -btrfs_leaf_ref_tree_init (&dirty->ref_tree); - dirty->ref_tree.generation = running_trans_id; root->commit_root =btrfs_root_node (root); - root->ref_tree = &dirty->ref_tree; + root->dirty_root = dirty;memcpy (dirty->root, root,sizeof (*root)); + dirty->root->ref_tree = &root->ref_tree_struct; +spin_lock_init (&dirty->root->node_lock);mutex_init (&dirty->root->objectid_mutex); dirty->root->node = root->commit_root;
@@ -333,6 +332,8 @@ int btrfs_commit_tree_roots(struct btrfslist_del_init (next); root = list_entry(next, struct btrfs_root, dirty_list);update_cowonly_root (trans, root); +if (root->fs_info->closing) +btrfs_remove_leaf_refs (root); }return 0 ; }
@@ -346,10 +347,8 @@ int btrfs_add_dead_root(struct btrfs_roo dirty =kmalloc (sizeof (*dirty),GFP_NOFS );if (!dirty)return -ENOMEM ; -btrfs_leaf_ref_tree_init (&dirty->ref_tree); dirty->root = root; dirty->latest_root = latest; - root->ref_tree =NULL ;list_add (&dirty->list, dead_list);return 0 ; }
@@ -379,18 +378,14 @@ static noinline int add_dirty_roots(stru BTRFS_ROOT_TRANS_TAG);BUG_ON (!root->ref_tree); - dirty = container_of(root->ref_tree, struct dirty_root, - ref_tree); + dirty = root->dirty_root;if (root->commit_root == root->node) {WARN_ON (root->node->start !=btrfs_root_bytenr (&root->root_item)); -BUG_ON (!btrfs_leaf_ref_tree_empty ( - root->ref_tree));free_extent_buffer (root->commit_root); root->commit_root =NULL ; - root->ref_tree =NULL ;kfree (dirty->root);kfree (dirty);
@@ -410,7 +405,6 @@ static noinline int add_dirty_roots(stru sizeof(struct btrfs_disk_key)); root->root_item.drop_level =0 ; root->commit_root =NULL ; - root->ref_tree =NULL ; root->root_key.offset = root->fs_info->generation;btrfs_set_root_bytenr (&root->root_item, root->node->start);
@@ -538,8 +532,6 @@ static noinline int drop_dirty_roots(str nr = trans->blocks_used; ret =btrfs_end_transaction (trans, tree_root);BUG_ON (ret); - -btrfs_remove_leaf_refs (dirty->root);free_extent_buffer (dirty->root->node);kfree (dirty->root);
@@ -725,10 +717,6 @@ int btrfs_commit_transaction(struct btrf &dirty_fs_roots);BUG_ON (ret); -spin_lock (&root->fs_info->ref_cache_lock); - root->fs_info->running_ref_cache_size =0 ; -spin_unlock (&root->fs_info->ref_cache_lock); - ret =btrfs_commit_tree_roots (trans, root);BUG_ON (ret);
Makefile +2 -1
@@ -6,7 +6,8 @@ btrfs-y := super.o ctree.o extent-tree.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
ctree.c +2 -2
@@ -165,7 +165,7 @@ int btrfs_copy_root(struct btrfs_trans_hbtrfs_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)
@@ -232,7 +232,7 @@ int __btrfs_cow_block(struct btrfs_transWARN_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 {
ctree.h +7 -1
@@ -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;
@@ -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;
@@ -1430,7 +1436,7 @@ int btrfs_reserve_extent(struct btrfs_tr 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,
disk-io.c +14 -0
@@ -716,6 +716,7 @@ static int __setup_root(u32 nodesize, u3 root->node =NULL ; root->inode =NULL ; root->commit_root =NULL ; + root->ref_tree =NULL ; root->sectorsize = sectorsize; root->nodesize = nodesize; root->leafsize = leafsize;
@@ -1165,12 +1166,19 @@ static int transaction_kthread(void *argvfs_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);
@@ -1233,6 +1241,7 @@ struct btrfs_root *open_ctree(struct supspin_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;
@@ -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);
extent-tree.c +106 -12
188 lines not on this page · raw message
transaction.c +50 -18
147 lines not on this page · raw message
ref-cache.c new file +195 -0
195 lines not on this page · raw message
ref-cache.h new file +71 -0
71 lines not on this page · raw message
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/1 initial version of reference cache
Hi all,
Quoted 9 lines · Chris Mason
Yan and I are hammering this out a little, I've attached my current patches.
I was seeing cache misses after long stress runs, which I think is coming from references on the higher levels of the tree making us skip some leaves while dropping the transaction that added them.
My new version using a single cache per root, and should avoid these misses.
Just curious, what is the cache size and or eviction policy? Is it LFU or LRU, fifo, something custom? Would ARC be a good policy for this purpose?
Sorry if this is totally off-topic or clueless, just curious.. hell, I'm not even shure what data/info/object is the cache for...
Kind regards,
--
Miguel Sousa Filipe
Quoted 10 lines · Miguel Sousa Filipe
Hi all,
Quoted 7 lines · Chris Mason
Yan and I are hammering this out a little, I've attached my current patches.
I was seeing cache misses after long stress runs, which I think is coming from references on the higher levels of the tree making us skip some leaves while dropping the transaction that added them.
Quoted 7 lines
Quoted 2 lines
My new version using a single cache per root, and should avoid these misses.
Just curious, what is the cache size and or eviction policy? Is it LFU or LRU, fifo, something custom? Would ARC be a good policy for this purpose?
Since this is a cache of the extents pointers in a COW block, things are only written once, and these items are only read once most of the time. So, we don't need anything fancy, just a direct access list that we can use to pull off really old things.
In this case, it is just a list head.
-chris
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: still see locking issues...
Quoted 4 lines · Ric Wheeler
Not sure if this is just an 8-way, multithreaded test, but my run of the latest unstable tree ground to a halt with lock messages (see the attached, compressed log for details ;-)) On the good news side, it did run for around 8 hours before the first message was logged.
I just merged Yan's missing hunks that might help explain this. At least for fs_mark, you shouldn't really be hitting the throttling code very often.
But, until I fully thread the allocator I can't completely get rid of the stalls. That's one of the first things on my list for after v0.16
One of your procs is stuck in generic_unplug_device, and that one didn't come from me ;) Sounds like the IO subsystem might be taking short breaks as well.
-chris
Re: still see locking issues...
In reply to a message not in the archiveQuoted 4 lines · Ric Wheeler
Not sure if this is just an 8-way, multithreaded test, but my run of the latest unstable tree ground to a halt with lock messages (see the attached, compressed log for details ;-)) On the good news side, it did run for around 8 hours before the first message was logged.
It also looks like writeback is getting stuck waiting for locked pages that are waiting for the transaction lock. I've changed around the start_transaction code a bit to help with this, and I'll test a bit and send out.
-chris