diff options
Diffstat (limited to 'fs/btrfs/ref-cache.c')
-rw-r--r-- | fs/btrfs/ref-cache.c | 71 |
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 | ||
47 | static int comp_keys(struct btrfs_key *k1, struct btrfs_key *k2) | 48 | static 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 | |||
64 | static 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 | ||
93 | static struct rb_node *tree_search(struct rb_root *root, struct btrfs_key *key) | 75 | static 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 | ||
142 | struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, | 122 | struct 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 | ||