blob: ec9587784a3dc2098e2073b3c9faff827a5d9bf1 [file] [log] [blame]
Yan Zheng31153d82008-07-28 15:32:19 -04001/*
2 * Copyright (C) 2008 Oracle. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
17 */
18
19#include <linux/sched.h>
20#include "ctree.h"
21#include "ref-cache.h"
22#include "transaction.h"
23
24struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(int nr_extents)
25{
26 struct btrfs_leaf_ref *ref;
27
28 ref = kmalloc(btrfs_leaf_ref_size(nr_extents), GFP_NOFS);
29 if (ref) {
30 memset(ref, 0, sizeof(*ref));
31 atomic_set(&ref->usage, 1);
Chris Mason017e5362008-07-28 15:32:51 -040032 INIT_LIST_HEAD(&ref->list);
Yan Zheng31153d82008-07-28 15:32:19 -040033 }
34 return ref;
35}
36
37void btrfs_free_leaf_ref(struct btrfs_leaf_ref *ref)
38{
39 if (!ref)
40 return;
41 WARN_ON(atomic_read(&ref->usage) == 0);
42 if (atomic_dec_and_test(&ref->usage)) {
43 BUG_ON(ref->in_tree);
44 kfree(ref);
45 }
46}
47
Chris Mason017e5362008-07-28 15:32:51 -040048static struct rb_node *tree_insert(struct rb_root *root, u64 bytenr,
Yan Zheng31153d82008-07-28 15:32:19 -040049 struct rb_node *node)
50{
51 struct rb_node ** p = &root->rb_node;
52 struct rb_node * parent = NULL;
53 struct btrfs_leaf_ref *entry;
Yan Zheng31153d82008-07-28 15:32:19 -040054
55 while(*p) {
56 parent = *p;
57 entry = rb_entry(parent, struct btrfs_leaf_ref, rb_node);
58 WARN_ON(!entry->in_tree);
59
Chris Mason017e5362008-07-28 15:32:51 -040060 if (bytenr < entry->bytenr)
Yan Zheng31153d82008-07-28 15:32:19 -040061 p = &(*p)->rb_left;
Chris Mason017e5362008-07-28 15:32:51 -040062 else if (bytenr > entry->bytenr)
Yan Zheng31153d82008-07-28 15:32:19 -040063 p = &(*p)->rb_right;
64 else
65 return parent;
66 }
67
68 entry = rb_entry(node, struct btrfs_leaf_ref, rb_node);
69 entry->in_tree = 1;
70 rb_link_node(node, parent, p);
71 rb_insert_color(node, root);
72 return NULL;
73}
74
Chris Mason017e5362008-07-28 15:32:51 -040075static struct rb_node *tree_search(struct rb_root *root, u64 bytenr)
Yan Zheng31153d82008-07-28 15:32:19 -040076{
77 struct rb_node * n = root->rb_node;
78 struct btrfs_leaf_ref *entry;
Yan Zheng31153d82008-07-28 15:32:19 -040079
80 while(n) {
81 entry = rb_entry(n, struct btrfs_leaf_ref, rb_node);
82 WARN_ON(!entry->in_tree);
83
Chris Mason017e5362008-07-28 15:32:51 -040084 if (bytenr < entry->bytenr)
Yan Zheng31153d82008-07-28 15:32:19 -040085 n = n->rb_left;
Chris Mason017e5362008-07-28 15:32:51 -040086 else if (bytenr > entry->bytenr)
Yan Zheng31153d82008-07-28 15:32:19 -040087 n = n->rb_right;
88 else
89 return n;
90 }
91 return NULL;
92}
93
94int btrfs_remove_leaf_refs(struct btrfs_root *root)
95{
96 struct rb_node *rb;
97 struct btrfs_leaf_ref *ref = NULL;
98 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
99
100 if (!tree)
101 return 0;
102
103 spin_lock(&tree->lock);
104 while(!btrfs_leaf_ref_tree_empty(tree)) {
Yan Zheng31153d82008-07-28 15:32:19 -0400105 rb = rb_first(&tree->root);
106 ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node);
107 rb_erase(&ref->rb_node, &tree->root);
108 ref->in_tree = 0;
Chris Mason017e5362008-07-28 15:32:51 -0400109 list_del_init(&ref->list);
Yan Zheng31153d82008-07-28 15:32:19 -0400110
111 spin_unlock(&tree->lock);
112
113 btrfs_free_leaf_ref(ref);
114
115 cond_resched();
116 spin_lock(&tree->lock);
117 }
118 spin_unlock(&tree->lock);
119 return 0;
120}
121
122struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root,
Chris Mason017e5362008-07-28 15:32:51 -0400123 u64 bytenr)
Yan Zheng31153d82008-07-28 15:32:19 -0400124{
125 struct rb_node *rb;
126 struct btrfs_leaf_ref *ref = NULL;
127 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
128
129 if (!tree)
130 return NULL;
131
132 spin_lock(&tree->lock);
Chris Mason017e5362008-07-28 15:32:51 -0400133 rb = tree_search(&tree->root, bytenr);
134 if (rb)
135 ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node);
Yan Zheng31153d82008-07-28 15:32:19 -0400136 if (ref)
137 atomic_inc(&ref->usage);
138 spin_unlock(&tree->lock);
139 return ref;
140}
141
142int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
143{
144 int ret = 0;
145 struct rb_node *rb;
146 size_t size = btrfs_leaf_ref_size(ref->nritems);
147 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
Yan Zheng31153d82008-07-28 15:32:19 -0400148
149 spin_lock(&tree->lock);
Chris Mason017e5362008-07-28 15:32:51 -0400150 rb = tree_insert(&tree->root, ref->bytenr, &ref->rb_node);
Yan Zheng31153d82008-07-28 15:32:19 -0400151 if (rb) {
152 ret = -EEXIST;
153 } else {
154 spin_lock(&root->fs_info->ref_cache_lock);
155 root->fs_info->total_ref_cache_size += size;
Yan Zheng31153d82008-07-28 15:32:19 -0400156 spin_unlock(&root->fs_info->ref_cache_lock);
Yan Zheng31153d82008-07-28 15:32:19 -0400157 atomic_inc(&ref->usage);
Chris Mason017e5362008-07-28 15:32:51 -0400158 list_add_tail(&ref->list, &tree->list);
Yan Zheng31153d82008-07-28 15:32:19 -0400159 }
160 spin_unlock(&tree->lock);
161 return ret;
162}
163
164int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
165{
166 size_t size = btrfs_leaf_ref_size(ref->nritems);
167 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
Yan Zheng31153d82008-07-28 15:32:19 -0400168
169 BUG_ON(!ref->in_tree);
170 spin_lock(&tree->lock);
171
172 spin_lock(&root->fs_info->ref_cache_lock);
173 root->fs_info->total_ref_cache_size -= size;
Yan Zheng31153d82008-07-28 15:32:19 -0400174 spin_unlock(&root->fs_info->ref_cache_lock);
175
Yan Zheng31153d82008-07-28 15:32:19 -0400176 rb_erase(&ref->rb_node, &tree->root);
177 ref->in_tree = 0;
Chris Mason017e5362008-07-28 15:32:51 -0400178 list_del_init(&ref->list);
Yan Zheng31153d82008-07-28 15:32:19 -0400179
180 spin_unlock(&tree->lock);
181
182 btrfs_free_leaf_ref(ref);
183 return 0;
184}
185