aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ref-cache.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-07-28 15:32:51 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:05 -0400
commit017e5369eb353559d68a11d4a718faa634533821 (patch)
treec339f2f4a59e403c7f9bfa8d137663c6bf260537 /fs/btrfs/ref-cache.c
parent31153d81284934601d08110ac7698fd9a535e4c0 (diff)
Btrfs: Leaf reference cache update
This changes the reference cache to make a single cache per root instead of one cache per transaction, and to key by the byte number of the disk block instead of the keys inside. This makes it much less likely to have cache misses if a snapshot or something has an extra reference on a higher node or a leaf while the first transaction that added the leaf into the cache is dropping. Some throttling is added to functions that free blocks heavily so they wait for old transactions to drop. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ref-cache.c')
-rw-r--r--fs/btrfs/ref-cache.c71
1 files changed, 15 insertions, 56 deletions
diff --git a/fs/btrfs/ref-cache.c b/fs/btrfs/ref-cache.c
index 95a9faeb9dc4..ec9587784a3d 100644
--- a/fs/btrfs/ref-cache.c
+++ b/fs/btrfs/ref-cache.c
@@ -29,6 +29,7 @@ struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(int nr_extents)
29 if (ref) { 29 if (ref) {
30 memset(ref, 0, sizeof(*ref)); 30 memset(ref, 0, sizeof(*ref));
31 atomic_set(&ref->usage, 1); 31 atomic_set(&ref->usage, 1);
32 INIT_LIST_HEAD(&ref->list);
32 } 33 }
33 return ref; 34 return ref;
34} 35}
@@ -44,40 +45,21 @@ void btrfs_free_leaf_ref(struct btrfs_leaf_ref *ref)
44 } 45 }
45} 46}
46 47
47static int comp_keys(struct btrfs_key *k1, struct btrfs_key *k2) 48static struct rb_node *tree_insert(struct rb_root *root, u64 bytenr,
48{
49 if (k1->objectid > k2->objectid)
50 return 1;
51 if (k1->objectid < k2->objectid)
52 return -1;
53 if (k1->type > k2->type)
54 return 1;
55 if (k1->type < k2->type)
56 return -1;
57 if (k1->offset > k2->offset)
58 return 1;
59 if (k1->offset < k2->offset)
60 return -1;
61 return 0;
62}
63
64static struct rb_node *tree_insert(struct rb_root *root, struct btrfs_key *key,
65 struct rb_node *node) 49 struct rb_node *node)
66{ 50{
67 struct rb_node ** p = &root->rb_node; 51 struct rb_node ** p = &root->rb_node;
68 struct rb_node * parent = NULL; 52 struct rb_node * parent = NULL;
69 struct btrfs_leaf_ref *entry; 53 struct btrfs_leaf_ref *entry;
70 int ret;
71 54
72 while(*p) { 55 while(*p) {
73 parent = *p; 56 parent = *p;
74 entry = rb_entry(parent, struct btrfs_leaf_ref, rb_node); 57 entry = rb_entry(parent, struct btrfs_leaf_ref, rb_node);
75 WARN_ON(!entry->in_tree); 58 WARN_ON(!entry->in_tree);
76 59
77 ret = comp_keys(key, &entry->key); 60 if (bytenr < entry->bytenr)
78 if (ret < 0)
79 p = &(*p)->rb_left; 61 p = &(*p)->rb_left;
80 else if (ret > 0) 62 else if (bytenr > entry->bytenr)
81 p = &(*p)->rb_right; 63 p = &(*p)->rb_right;
82 else 64 else
83 return parent; 65 return parent;
@@ -90,20 +72,18 @@ static struct rb_node *tree_insert(struct rb_root *root, struct btrfs_key *key,
90 return NULL; 72 return NULL;
91} 73}
92 74
93static struct rb_node *tree_search(struct rb_root *root, struct btrfs_key *key) 75static struct rb_node *tree_search(struct rb_root *root, u64 bytenr)
94{ 76{
95 struct rb_node * n = root->rb_node; 77 struct rb_node * n = root->rb_node;
96 struct btrfs_leaf_ref *entry; 78 struct btrfs_leaf_ref *entry;
97 int ret;
98 79
99 while(n) { 80 while(n) {
100 entry = rb_entry(n, struct btrfs_leaf_ref, rb_node); 81 entry = rb_entry(n, struct btrfs_leaf_ref, rb_node);
101 WARN_ON(!entry->in_tree); 82 WARN_ON(!entry->in_tree);
102 83
103 ret = comp_keys(key, &entry->key); 84 if (bytenr < entry->bytenr)
104 if (ret < 0)
105 n = n->rb_left; 85 n = n->rb_left;
106 else if (ret > 0) 86 else if (bytenr > entry->bytenr)
107 n = n->rb_right; 87 n = n->rb_right;
108 else 88 else
109 return n; 89 return n;
@@ -122,11 +102,11 @@ int btrfs_remove_leaf_refs(struct btrfs_root *root)
122 102
123 spin_lock(&tree->lock); 103 spin_lock(&tree->lock);
124 while(!btrfs_leaf_ref_tree_empty(tree)) { 104 while(!btrfs_leaf_ref_tree_empty(tree)) {
125 tree->last = NULL;
126 rb = rb_first(&tree->root); 105 rb = rb_first(&tree->root);
127 ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node); 106 ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node);
128 rb_erase(&ref->rb_node, &tree->root); 107 rb_erase(&ref->rb_node, &tree->root);
129 ref->in_tree = 0; 108 ref->in_tree = 0;
109 list_del_init(&ref->list);
130 110
131 spin_unlock(&tree->lock); 111 spin_unlock(&tree->lock);
132 112
@@ -140,7 +120,7 @@ int btrfs_remove_leaf_refs(struct btrfs_root *root)
140} 120}
141 121
142struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, 122struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root,
143 struct btrfs_key *key) 123 u64 bytenr)
144{ 124{
145 struct rb_node *rb; 125 struct rb_node *rb;
146 struct btrfs_leaf_ref *ref = NULL; 126 struct btrfs_leaf_ref *ref = NULL;
@@ -150,15 +130,9 @@ struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root,
150 return NULL; 130 return NULL;
151 131
152 spin_lock(&tree->lock); 132 spin_lock(&tree->lock);
153 if (tree->last && comp_keys(key, &tree->last->key) == 0) { 133 rb = tree_search(&tree->root, bytenr);
154 ref = tree->last; 134 if (rb)
155 } else { 135 ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node);
156 rb = tree_search(&tree->root, key);
157 if (rb) {
158 ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node);
159 tree->last = ref;
160 }
161 }
162 if (ref) 136 if (ref)
163 atomic_inc(&ref->usage); 137 atomic_inc(&ref->usage);
164 spin_unlock(&tree->lock); 138 spin_unlock(&tree->lock);
@@ -171,21 +145,17 @@ int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
171 struct rb_node *rb; 145 struct rb_node *rb;
172 size_t size = btrfs_leaf_ref_size(ref->nritems); 146 size_t size = btrfs_leaf_ref_size(ref->nritems);
173 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 147 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
174 struct btrfs_transaction *trans = root->fs_info->running_transaction;
175 148
176 spin_lock(&tree->lock); 149 spin_lock(&tree->lock);
177 rb = tree_insert(&tree->root, &ref->key, &ref->rb_node); 150 rb = tree_insert(&tree->root, ref->bytenr, &ref->rb_node);
178 if (rb) { 151 if (rb) {
179 ret = -EEXIST; 152 ret = -EEXIST;
180 } else { 153 } else {
181 spin_lock(&root->fs_info->ref_cache_lock); 154 spin_lock(&root->fs_info->ref_cache_lock);
182 root->fs_info->total_ref_cache_size += size; 155 root->fs_info->total_ref_cache_size += size;
183 if (trans && tree->generation == trans->transid)
184 root->fs_info->running_ref_cache_size += size;
185 spin_unlock(&root->fs_info->ref_cache_lock); 156 spin_unlock(&root->fs_info->ref_cache_lock);
186
187 tree->last = ref;
188 atomic_inc(&ref->usage); 157 atomic_inc(&ref->usage);
158 list_add_tail(&ref->list, &tree->list);
189 } 159 }
190 spin_unlock(&tree->lock); 160 spin_unlock(&tree->lock);
191 return ret; 161 return ret;
@@ -195,28 +165,17 @@ int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
195{ 165{
196 size_t size = btrfs_leaf_ref_size(ref->nritems); 166 size_t size = btrfs_leaf_ref_size(ref->nritems);
197 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 167 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
198 struct btrfs_transaction *trans = root->fs_info->running_transaction;
199 168
200 BUG_ON(!ref->in_tree); 169 BUG_ON(!ref->in_tree);
201 spin_lock(&tree->lock); 170 spin_lock(&tree->lock);
202 171
203 spin_lock(&root->fs_info->ref_cache_lock); 172 spin_lock(&root->fs_info->ref_cache_lock);
204 root->fs_info->total_ref_cache_size -= size; 173 root->fs_info->total_ref_cache_size -= size;
205 if (trans && tree->generation == trans->transid)
206 root->fs_info->running_ref_cache_size -= size;
207 spin_unlock(&root->fs_info->ref_cache_lock); 174 spin_unlock(&root->fs_info->ref_cache_lock);
208 175
209 if (tree->last == ref) {
210 struct rb_node *next = rb_next(&ref->rb_node);
211 if (next) {
212 tree->last = rb_entry(next, struct btrfs_leaf_ref,
213 rb_node);
214 } else
215 tree->last = NULL;
216 }
217
218 rb_erase(&ref->rb_node, &tree->root); 176 rb_erase(&ref->rb_node, &tree->root);
219 ref->in_tree = 0; 177 ref->in_tree = 0;
178 list_del_init(&ref->list);
220 179
221 spin_unlock(&tree->lock); 180 spin_unlock(&tree->lock);
222 181