aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-03-26 10:15:30 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-03-26 10:15:30 -0400
commit8ef97622caa2d5f78d1dc58ab918e2fbfa9b357a (patch)
tree6ae74ce8ff1ba7a6b8a522ed0ea3b37f17a6b305 /fs
parentf7922033efe957f79ae57f6026e93c8148e7f7ed (diff)
Btrfs: add a radix back bit tree
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/Makefile3
-rw-r--r--fs/btrfs/bit-radix.c107
-rw-r--r--fs/btrfs/bit-radix.h15
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/disk-io.c3
-rw-r--r--fs/btrfs/extent-tree.c93
6 files changed, 167 insertions, 57 deletions
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index be7d74cdca04..5346f706b2c5 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -3,7 +3,8 @@ ifneq ($(KERNELRELEASE),)
3 3
4obj-m := btrfs.o 4obj-m := btrfs.o
5btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ 5btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
6 hash.o file-item.o inode-item.o inode-map.o disk-io.o transaction.o 6 hash.o file-item.o inode-item.o inode-map.o disk-io.o \
7 transaction.o bit-radix.o
7 8
8#btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ 9#btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
9# root-tree.o dir-item.o hash.o file-item.o inode-item.o \ 10# root-tree.o dir-item.o hash.o file-item.o inode-item.o \
diff --git a/fs/btrfs/bit-radix.c b/fs/btrfs/bit-radix.c
new file mode 100644
index 000000000000..43807cc3cce7
--- /dev/null
+++ b/fs/btrfs/bit-radix.c
@@ -0,0 +1,107 @@
1#include <linux/module.h>
2#include "bit-radix.h"
3
4#define BIT_ARRAY_BYTES 256
5#define BIT_RADIX_BITS_PER_ARRAY ((BIT_ARRAY_BYTES - sizeof(unsigned long)) * 8)
6
7int set_radix_bit(struct radix_tree_root *radix, unsigned long bit)
8{
9 unsigned long *bits;
10 unsigned long slot;
11 int bit_slot;
12 int ret;
13
14 slot = bit / BIT_RADIX_BITS_PER_ARRAY;
15 bit_slot = bit % BIT_RADIX_BITS_PER_ARRAY;
16
17 bits = radix_tree_lookup(radix, slot);
18 if (!bits) {
19 bits = kmalloc(BIT_ARRAY_BYTES, GFP_NOIO);
20 if (!bits)
21 return -ENOMEM;
22 memset(bits + 1, 0, BIT_ARRAY_BYTES - sizeof(unsigned long));
23 bits[0] = slot;
24 ret = radix_tree_insert(radix, slot, bits);
25 if (ret)
26 return ret;
27 }
28 set_bit(bit_slot, bits + 1);
29 return 0;
30}
31
32int test_radix_bit(struct radix_tree_root *radix, unsigned long bit)
33{
34 unsigned long *bits;
35 unsigned long slot;
36 int bit_slot;
37
38 slot = bit / BIT_RADIX_BITS_PER_ARRAY;
39 bit_slot = bit % BIT_RADIX_BITS_PER_ARRAY;
40
41 bits = radix_tree_lookup(radix, slot);
42 if (!bits)
43 return 0;
44 return test_bit(bit_slot, bits + 1);
45}
46
47int clear_radix_bit(struct radix_tree_root *radix, unsigned long bit)
48{
49 unsigned long *bits;
50 unsigned long slot;
51 int bit_slot;
52 int i;
53 int empty = 1;
54
55 slot = bit / BIT_RADIX_BITS_PER_ARRAY;
56 bit_slot = bit % BIT_RADIX_BITS_PER_ARRAY;
57
58 bits = radix_tree_lookup(radix, slot);
59 if (!bits)
60 return 0;
61 clear_bit(bit_slot, bits + 1);
62
63 for (i = 1; i < BIT_ARRAY_BYTES / sizeof(unsigned long); i++) {
64 if (bits[i]) {
65 empty = 0;
66 break;
67 }
68 }
69
70 if (empty) {
71 bits = radix_tree_delete(radix, slot);
72 BUG_ON(!bits);
73 }
74 return 0;
75}
76
77int find_first_radix_bit(struct radix_tree_root *radix, unsigned long *retbits,
78 int nr)
79{
80 unsigned long *bits;
81 unsigned long *gang[4];
82 int found;
83 int ret;
84 int i;
85 int total_found = 0;
86
87 ret = radix_tree_gang_lookup(radix, (void *)&gang, 0, ARRAY_SIZE(gang));
88 for (i = 0; i < ret && nr > 0; i++) {
89 found = 0;
90 bits = gang[i];
91 while(nr > 0) {
92 found = find_next_bit(bits + 1,
93 BIT_RADIX_BITS_PER_ARRAY,
94 found);
95 if (found < BIT_RADIX_BITS_PER_ARRAY) {
96 *retbits = bits[0] *
97 BIT_RADIX_BITS_PER_ARRAY + found;
98 retbits++;
99 nr--;
100 total_found++;
101 found++;
102 } else
103 break;
104 }
105 }
106 return total_found;
107}
diff --git a/fs/btrfs/bit-radix.h b/fs/btrfs/bit-radix.h
new file mode 100644
index 000000000000..56aad4c7d7f7
--- /dev/null
+++ b/fs/btrfs/bit-radix.h
@@ -0,0 +1,15 @@
1#ifndef __BIT_RADIX__
2#define __BIT_RADIX__
3#include <linux/radix-tree.h>
4
5int set_radix_bit(struct radix_tree_root *radix, unsigned long bit);
6int test_radix_bit(struct radix_tree_root *radix, unsigned long bit);
7int clear_radix_bit(struct radix_tree_root *radix, unsigned long bit);
8int find_first_radix_bit(struct radix_tree_root *radix, unsigned long *retbits,
9 int nr);
10
11static inline void init_bit_radix(struct radix_tree_root *radix)
12{
13 INIT_RADIX_TREE(radix, GFP_NOFS);
14}
15#endif
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 68cafae6a850..0aa1052d9f67 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1,8 +1,8 @@
1#ifndef __BTRFS__ 1#ifndef __BTRFS__
2#define __BTRFS__ 2#define __BTRFS__
3 3
4#include <linux/radix-tree.h>
5#include <linux/fs.h> 4#include <linux/fs.h>
5#include "bit-radix.h"
6 6
7struct btrfs_trans_handle; 7struct btrfs_trans_handle;
8struct btrfs_transaction; 8struct btrfs_transaction;
@@ -222,6 +222,7 @@ struct btrfs_fs_info {
222 struct btrfs_root *inode_root; 222 struct btrfs_root *inode_root;
223 struct btrfs_key current_insert; 223 struct btrfs_key current_insert;
224 struct btrfs_key last_insert; 224 struct btrfs_key last_insert;
225 struct radix_tree_root pending_del_radix;
225 struct radix_tree_root pinned_radix; 226 struct radix_tree_root pinned_radix;
226 u64 last_inode_alloc; 227 u64 last_inode_alloc;
227 u64 last_inode_alloc_dirid; 228 u64 last_inode_alloc_dirid;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index e32ddff55b0e..758a62aba063 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -104,7 +104,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
104 /* FIXME: don't be stupid */ 104 /* FIXME: don't be stupid */
105 if (!btrfs_super_root(disk_super)) 105 if (!btrfs_super_root(disk_super))
106 return NULL; 106 return NULL;
107 INIT_RADIX_TREE(&fs_info->pinned_radix, GFP_KERNEL); 107 init_bit_radix(&fs_info->pinned_radix);
108 init_bit_radix(&fs_info->pending_del_radix);
108 fs_info->running_transaction = NULL; 109 fs_info->running_transaction = NULL;
109 fs_info->fs_root = root; 110 fs_info->fs_root = root;
110 fs_info->tree_root = tree_root; 111 fs_info->tree_root = tree_root;
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 369b960fce45..b14104276eea 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1,5 +1,4 @@
1#include <linux/module.h> 1#include <linux/module.h>
2#include <linux/radix-tree.h>
3#include "ctree.h" 2#include "ctree.h"
4#include "disk-io.h" 3#include "disk-io.h"
5#include "print-tree.h" 4#include "print-tree.h"
@@ -12,15 +11,6 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
12 btrfs_root *extent_root); 11 btrfs_root *extent_root);
13static int del_pending_extents(struct btrfs_trans_handle *trans, struct 12static int del_pending_extents(struct btrfs_trans_handle *trans, struct
14 btrfs_root *extent_root); 13 btrfs_root *extent_root);
15/*
16 * pending extents are blocks that we're trying to allocate in the extent
17 * map while trying to grow the map because of other allocations. To avoid
18 * recursing, they are tagged in the radix tree and cleaned up after
19 * other allocations are done. The pending tag is also used in the same
20 * manner for deletes.
21 */
22#define CTREE_EXTENT_PENDING_DEL 0
23#define CTREE_EXTENT_PINNED 1
24 14
25static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root 15static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
26 *root, u64 blocknr) 16 *root, u64 blocknr)
@@ -104,24 +94,21 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
104int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct 94int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
105 btrfs_root *root) 95 btrfs_root *root)
106{ 96{
107 struct buffer_head *gang[8]; 97 unsigned long gang[8];
108 u64 first = 0; 98 u64 first = 0;
109 int ret; 99 int ret;
110 int i; 100 int i;
101 struct radix_tree_root *pinned_radix = &root->fs_info->pinned_radix;
111 102
112 while(1) { 103 while(1) {
113 ret = radix_tree_gang_lookup_tag(&root->fs_info->pinned_radix, 104 ret = find_first_radix_bit(pinned_radix, gang,
114 (void **)gang, 0, 105 ARRAY_SIZE(gang));
115 ARRAY_SIZE(gang),
116 CTREE_EXTENT_PINNED);
117 if (!ret) 106 if (!ret)
118 break; 107 break;
119 if (!first) 108 if (!first)
120 first = gang[0]->b_blocknr; 109 first = gang[0];
121 for (i = 0; i < ret; i++) { 110 for (i = 0; i < ret; i++) {
122 radix_tree_delete(&root->fs_info->pinned_radix, 111 clear_radix_bit(pinned_radix, gang[i]);
123 gang[i]->b_blocknr);
124 brelse(gang[i]);
125 } 112 }
126 } 113 }
127 if (root->fs_info->last_insert.objectid > first) 114 if (root->fs_info->last_insert.objectid > first)
@@ -161,29 +148,27 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
161 return 0; 148 return 0;
162} 149}
163 150
164static int pin_down_block(struct btrfs_root *root, u64 blocknr, int tag) 151static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending)
165{ 152{
166 int err; 153 int err;
167 struct buffer_head *bh = sb_getblk(root->fs_info->sb, blocknr);
168 struct btrfs_header *header; 154 struct btrfs_header *header;
169 BUG_ON(!bh); 155 struct buffer_head *bh;
170 156
171 header = btrfs_buffer_header(bh); 157 bh = sb_find_get_block(root->fs_info->sb, blocknr);
172 if (btrfs_header_generation(header) == 158 if (bh) {
173 root->fs_info->running_transaction->transid) { 159 header = btrfs_buffer_header(bh);
174 return 0; 160 if (btrfs_header_generation(header) ==
175 } 161 root->fs_info->running_transaction->transid) {
176 162 brelse(bh);
177 err = radix_tree_insert(&root->fs_info->pinned_radix, 163 return 0;
178 blocknr, bh); 164 }
179 if (err && err != -EEXIST) {
180 BUG();
181 return err;
182 }
183 if (err == -EEXIST)
184 brelse(bh); 165 brelse(bh);
185 radix_tree_tag_set(&root->fs_info->pinned_radix, blocknr, 166 }
186 tag); 167 if (pending)
168 err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr);
169 else
170 err = set_radix_bit(&root->fs_info->pinned_radix, blocknr);
171 BUG_ON(err);
187 return 0; 172 return 0;
188} 173}
189 174
@@ -225,8 +210,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
225 u64 super_blocks_used; 210 u64 super_blocks_used;
226 211
227 if (pin) { 212 if (pin) {
228 ret = pin_down_block(root, blocknr, 213 ret = pin_down_block(root, blocknr, 0);
229 CTREE_EXTENT_PINNED);
230 BUG_ON(ret); 214 BUG_ON(ret);
231 } 215 }
232 216
@@ -255,25 +239,26 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
255 int ret; 239 int ret;
256 int wret; 240 int wret;
257 int err = 0; 241 int err = 0;
258 struct buffer_head *gang[4]; 242 unsigned long gang[4];
259 int i; 243 int i;
260 struct radix_tree_root *radix = &extent_root->fs_info->pinned_radix; 244 struct radix_tree_root *pending_radix;
245 struct radix_tree_root *pinned_radix;
246
247 pending_radix = &extent_root->fs_info->pending_del_radix;
248 pinned_radix = &extent_root->fs_info->pinned_radix;
261 249
262 while(1) { 250 while(1) {
263 ret = radix_tree_gang_lookup_tag( 251 ret = find_first_radix_bit(pending_radix, gang,
264 &extent_root->fs_info->pinned_radix, 252 ARRAY_SIZE(gang));
265 (void **)gang, 0,
266 ARRAY_SIZE(gang),
267 CTREE_EXTENT_PENDING_DEL);
268 if (!ret) 253 if (!ret)
269 break; 254 break;
270 for (i = 0; i < ret; i++) { 255 for (i = 0; i < ret; i++) {
271 radix_tree_tag_set(radix, gang[i]->b_blocknr, 256 wret = set_radix_bit(pinned_radix, gang[i]);
272 CTREE_EXTENT_PINNED); 257 BUG_ON(wret);
273 radix_tree_tag_clear(radix, gang[i]->b_blocknr, 258 wret = clear_radix_bit(pending_radix, gang[i]);
274 CTREE_EXTENT_PENDING_DEL); 259 BUG_ON(wret);
275 wret = __free_extent(trans, extent_root, 260 wret = __free_extent(trans, extent_root,
276 gang[i]->b_blocknr, 1, 0); 261 gang[i], 1, 0);
277 if (wret) 262 if (wret)
278 err = wret; 263 err = wret;
279 } 264 }
@@ -294,7 +279,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
294 279
295 if (root == extent_root) { 280 if (root == extent_root) {
296 t = find_tree_block(root, blocknr); 281 t = find_tree_block(root, blocknr);
297 pin_down_block(root, blocknr, CTREE_EXTENT_PENDING_DEL); 282 pin_down_block(root, blocknr, 1);
298 return 0; 283 return 0;
299 } 284 }
300 ret = __free_extent(trans, root, blocknr, num_blocks, pin); 285 ret = __free_extent(trans, root, blocknr, num_blocks, pin);
@@ -393,7 +378,7 @@ check_pending:
393 BUG_ON(ins->objectid < search_start); 378 BUG_ON(ins->objectid < search_start);
394 for (test_block = ins->objectid; 379 for (test_block = ins->objectid;
395 test_block < ins->objectid + total_needed; test_block++) { 380 test_block < ins->objectid + total_needed; test_block++) {
396 if (radix_tree_lookup(&root->fs_info->pinned_radix, 381 if (test_radix_bit(&root->fs_info->pinned_radix,
397 test_block)) { 382 test_block)) {
398 search_start = test_block + 1; 383 search_start = test_block + 1;
399 goto check_failed; 384 goto check_failed;