diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-03-26 10:15:30 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-03-26 10:15:30 -0400 |
commit | 8ef97622caa2d5f78d1dc58ab918e2fbfa9b357a (patch) | |
tree | 6ae74ce8ff1ba7a6b8a522ed0ea3b37f17a6b305 /fs | |
parent | f7922033efe957f79ae57f6026e93c8148e7f7ed (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/Makefile | 3 | ||||
-rw-r--r-- | fs/btrfs/bit-radix.c | 107 | ||||
-rw-r--r-- | fs/btrfs/bit-radix.h | 15 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 3 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 93 |
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 | ||
4 | obj-m := btrfs.o | 4 | obj-m := btrfs.o |
5 | btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ | 5 | btrfs-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 | |||
7 | int 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 | |||
32 | int 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 | |||
47 | int 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 | |||
77 | int 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 | |||
5 | int set_radix_bit(struct radix_tree_root *radix, unsigned long bit); | ||
6 | int test_radix_bit(struct radix_tree_root *radix, unsigned long bit); | ||
7 | int clear_radix_bit(struct radix_tree_root *radix, unsigned long bit); | ||
8 | int find_first_radix_bit(struct radix_tree_root *radix, unsigned long *retbits, | ||
9 | int nr); | ||
10 | |||
11 | static 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 | ||
7 | struct btrfs_trans_handle; | 7 | struct btrfs_trans_handle; |
8 | struct btrfs_transaction; | 8 | struct 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); |
13 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct | 12 | static 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 | ||
25 | static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root | 15 | static 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, | |||
104 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | 94 | int 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 | ||
164 | static int pin_down_block(struct btrfs_root *root, u64 blocknr, int tag) | 151 | static 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; |