aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ref-cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/ref-cache.c')
-rw-r--r--fs/btrfs/ref-cache.c58
1 files changed, 38 insertions, 20 deletions
diff --git a/fs/btrfs/ref-cache.c b/fs/btrfs/ref-cache.c
index 272b9890c982..c5809988c875 100644
--- a/fs/btrfs/ref-cache.c
+++ b/fs/btrfs/ref-cache.c
@@ -78,7 +78,6 @@ static struct rb_node *tree_insert(struct rb_root *root, u64 bytenr,
78 } 78 }
79 79
80 entry = rb_entry(node, struct btrfs_leaf_ref, rb_node); 80 entry = rb_entry(node, struct btrfs_leaf_ref, rb_node);
81 entry->in_tree = 1;
82 rb_link_node(node, parent, p); 81 rb_link_node(node, parent, p);
83 rb_insert_color(node, root); 82 rb_insert_color(node, root);
84 return NULL; 83 return NULL;
@@ -103,23 +102,29 @@ static struct rb_node *tree_search(struct rb_root *root, u64 bytenr)
103 return NULL; 102 return NULL;
104} 103}
105 104
106int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen) 105int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen,
106 int shared)
107{ 107{
108 struct btrfs_leaf_ref *ref = NULL; 108 struct btrfs_leaf_ref *ref = NULL;
109 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 109 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
110 110
111 if (shared)
112 tree = &root->fs_info->shared_ref_tree;
111 if (!tree) 113 if (!tree)
112 return 0; 114 return 0;
113 115
114 spin_lock(&tree->lock); 116 spin_lock(&tree->lock);
115 while(!list_empty(&tree->list)) { 117 while(!list_empty(&tree->list)) {
116 ref = list_entry(tree->list.next, struct btrfs_leaf_ref, list); 118 ref = list_entry(tree->list.next, struct btrfs_leaf_ref, list);
117 BUG_ON(!ref->in_tree); 119 BUG_ON(ref->tree != tree);
118 if (ref->root_gen > max_root_gen) 120 if (ref->root_gen > max_root_gen)
119 break; 121 break;
122 if (!xchg(&ref->in_tree, 0)) {
123 cond_resched_lock(&tree->lock);
124 continue;
125 }
120 126
121 rb_erase(&ref->rb_node, &tree->root); 127 rb_erase(&ref->rb_node, &tree->root);
122 ref->in_tree = 0;
123 list_del_init(&ref->list); 128 list_del_init(&ref->list);
124 129
125 spin_unlock(&tree->lock); 130 spin_unlock(&tree->lock);
@@ -137,32 +142,43 @@ struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root,
137 struct rb_node *rb; 142 struct rb_node *rb;
138 struct btrfs_leaf_ref *ref = NULL; 143 struct btrfs_leaf_ref *ref = NULL;
139 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 144 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
140 145again:
141 if (!tree) 146 if (tree) {
142 return NULL; 147 spin_lock(&tree->lock);
143 148 rb = tree_search(&tree->root, bytenr);
144 spin_lock(&tree->lock); 149 if (rb)
145 rb = tree_search(&tree->root, bytenr); 150 ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node);
146 if (rb) 151 if (ref)
147 ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node); 152 atomic_inc(&ref->usage);
148 if (ref) 153 spin_unlock(&tree->lock);
149 atomic_inc(&ref->usage); 154 if (ref)
150 spin_unlock(&tree->lock); 155 return ref;
151 return ref; 156 }
157 if (tree != &root->fs_info->shared_ref_tree) {
158 tree = &root->fs_info->shared_ref_tree;
159 goto again;
160 }
161 return NULL;
152} 162}
153 163
154int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref) 164int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref,
165 int shared)
155{ 166{
156 int ret = 0; 167 int ret = 0;
157 struct rb_node *rb; 168 struct rb_node *rb;
158 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 169 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
159 170
171 if (shared)
172 tree = &root->fs_info->shared_ref_tree;
173
160 spin_lock(&tree->lock); 174 spin_lock(&tree->lock);
161 rb = tree_insert(&tree->root, ref->bytenr, &ref->rb_node); 175 rb = tree_insert(&tree->root, ref->bytenr, &ref->rb_node);
162 if (rb) { 176 if (rb) {
163 ret = -EEXIST; 177 ret = -EEXIST;
164 } else { 178 } else {
165 atomic_inc(&ref->usage); 179 atomic_inc(&ref->usage);
180 ref->tree = tree;
181 ref->in_tree = 1;
166 list_add_tail(&ref->list, &tree->list); 182 list_add_tail(&ref->list, &tree->list);
167 } 183 }
168 spin_unlock(&tree->lock); 184 spin_unlock(&tree->lock);
@@ -171,13 +187,15 @@ int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
171 187
172int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref) 188int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
173{ 189{
174 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 190 struct btrfs_leaf_ref_tree *tree;
191
192 if (!xchg(&ref->in_tree, 0))
193 return 0;
175 194
176 BUG_ON(!ref->in_tree); 195 tree = ref->tree;
177 spin_lock(&tree->lock); 196 spin_lock(&tree->lock);
178 197
179 rb_erase(&ref->rb_node, &tree->root); 198 rb_erase(&ref->rb_node, &tree->root);
180 ref->in_tree = 0;
181 list_del_init(&ref->list); 199 list_del_init(&ref->list);
182 200
183 spin_unlock(&tree->lock); 201 spin_unlock(&tree->lock);