diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/Makefile | 50 | ||||
-rw-r--r-- | fs/btrfs/ctree.c | 6 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 15 | ||||
-rw-r--r-- | fs/btrfs/debug-tree.c | 38 | ||||
-rw-r--r-- | fs/btrfs/dir-item.c | 12 | ||||
-rw-r--r-- | fs/btrfs/dir-test.c | 494 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 17 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 1 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 10 | ||||
-rw-r--r-- | fs/btrfs/file-item.c | 6 | ||||
-rw-r--r-- | fs/btrfs/hash.c | 1 | ||||
-rw-r--r-- | fs/btrfs/hasher.c | 23 | ||||
-rw-r--r-- | fs/btrfs/inode-item.c | 5 | ||||
-rw-r--r-- | fs/btrfs/inode-map.c | 5 | ||||
-rw-r--r-- | fs/btrfs/kerncompat.h | 96 | ||||
-rw-r--r-- | fs/btrfs/list.h | 418 | ||||
-rw-r--r-- | fs/btrfs/mkfs.c | 255 | ||||
-rw-r--r-- | fs/btrfs/print-tree.c | 30 | ||||
-rw-r--r-- | fs/btrfs/quick-test.c | 179 | ||||
-rw-r--r-- | fs/btrfs/radix-tree.c | 836 | ||||
-rw-r--r-- | fs/btrfs/radix-tree.h | 73 | ||||
-rw-r--r-- | fs/btrfs/random-test.c | 405 | ||||
-rw-r--r-- | fs/btrfs/root-tree.c | 5 | ||||
-rw-r--r-- | fs/btrfs/super.c | 205 |
24 files changed, 274 insertions, 2911 deletions
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index 0720169b6d66..99e45a54ebd6 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile | |||
@@ -1,40 +1,20 @@ | |||
1 | CC=gcc | 1 | ifneq ($(KERNELRELEASE),) |
2 | CFLAGS = -g -Wall -Werror | 2 | # kbuild part of makefile |
3 | headers = radix-tree.h ctree.h disk-io.h kerncompat.h print-tree.h list.h \ | ||
4 | transaction.h | ||
5 | objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ | ||
6 | root-tree.o dir-item.o hash.o file-item.o inode-item.o \ | ||
7 | inode-map.o \ | ||
8 | 3 | ||
9 | # if you don't have sparse installed, use ls instead | 4 | obj-m := btrfs.o |
10 | CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \ | 5 | btrfs-y := super.o |
11 | -Wcontext -Wcast-truncate -Wuninitialized -Wshadow -Wundef | ||
12 | check=sparse $(CHECKFLAGS) | ||
13 | #check=ls | ||
14 | 6 | ||
15 | .c.o: | 7 | #btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ |
16 | $(check) $< | 8 | # root-tree.o dir-item.o hash.o file-item.o inode-item.o \ |
17 | $(CC) $(CFLAGS) -c $< | 9 | # inode-map.o \ |
18 | 10 | ||
19 | all: tester debug-tree quick-test dir-test tags mkfs.btrfs | 11 | else |
20 | |||
21 | mkfs.btrfs: $(objects) mkfs.o | ||
22 | gcc $(CFLAGS) -o mkfs.btrfs $(objects) mkfs.o | ||
23 | |||
24 | debug-tree: $(objects) debug-tree.o | ||
25 | gcc $(CFLAGS) -o debug-tree $(objects) debug-tree.o | ||
26 | |||
27 | tester: $(objects) random-test.o | ||
28 | gcc $(CFLAGS) -o tester $(objects) random-test.o | ||
29 | |||
30 | dir-test: $(objects) dir-test.o | ||
31 | gcc $(CFLAGS) -o dir-test $(objects) dir-test.o | ||
32 | quick-test: $(objects) quick-test.o | ||
33 | gcc $(CFLAGS) -o quick-test $(objects) quick-test.o | ||
34 | |||
35 | $(objects): $(headers) | ||
36 | |||
37 | clean : | ||
38 | rm debug-tree tester *.o | ||
39 | 12 | ||
13 | # Normal Makefile | ||
40 | 14 | ||
15 | KERNELDIR := /lib/modules/`uname -r`/build | ||
16 | all:: | ||
17 | $(MAKE) -C $(KERNELDIR) M=`pwd` modules | ||
18 | clean:: | ||
19 | rm *.o btrfs.ko | ||
20 | endif | ||
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 32922643b5bc..9fbd07c37fde 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -1,10 +1,6 @@ | |||
1 | #include <stdio.h> | 1 | #include <linux/module.h> |
2 | #include <stdlib.h> | ||
3 | #include "kerncompat.h" | ||
4 | #include "radix-tree.h" | ||
5 | #include "ctree.h" | 2 | #include "ctree.h" |
6 | #include "disk-io.h" | 3 | #include "disk-io.h" |
7 | #include "print-tree.h" | ||
8 | 4 | ||
9 | static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root | 5 | static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root |
10 | *root, struct btrfs_path *path, int level); | 6 | *root, struct btrfs_path *path, int level); |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 1a4d1d6fa401..ae8518cb94bf 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1,9 +1,6 @@ | |||
1 | #ifndef __BTRFS__ | 1 | #ifndef __BTRFS__ |
2 | #define __BTRFS__ | 2 | #define __BTRFS__ |
3 | 3 | ||
4 | #include "list.h" | ||
5 | #include "kerncompat.h" | ||
6 | |||
7 | struct btrfs_trans_handle; | 4 | struct btrfs_trans_handle; |
8 | 5 | ||
9 | #define BTRFS_MAGIC "_BtRfS_M" | 6 | #define BTRFS_MAGIC "_BtRfS_M" |
@@ -75,6 +72,7 @@ struct btrfs_super_block { | |||
75 | __le64 root; | 72 | __le64 root; |
76 | __le64 total_blocks; | 73 | __le64 total_blocks; |
77 | __le64 blocks_used; | 74 | __le64 blocks_used; |
75 | __le64 root_dir_objectid; | ||
78 | } __attribute__ ((__packed__)); | 76 | } __attribute__ ((__packed__)); |
79 | 77 | ||
80 | /* | 78 | /* |
@@ -693,6 +691,17 @@ static inline void btrfs_set_super_blocksize(struct btrfs_super_block *s, | |||
693 | s->blocksize = cpu_to_le32(val); | 691 | s->blocksize = cpu_to_le32(val); |
694 | } | 692 | } |
695 | 693 | ||
694 | static inline u64 btrfs_super_root_dir(struct btrfs_super_block *s) | ||
695 | { | ||
696 | return le64_to_cpu(s->root_dir_objectid); | ||
697 | } | ||
698 | |||
699 | static inline void btrfs_set_super_root_dir(struct btrfs_super_block *s, u64 | ||
700 | val) | ||
701 | { | ||
702 | s->root_dir_objectid = cpu_to_le64(val); | ||
703 | } | ||
704 | |||
696 | static inline u8 *btrfs_leaf_data(struct btrfs_leaf *l) | 705 | static inline u8 *btrfs_leaf_data(struct btrfs_leaf *l) |
697 | { | 706 | { |
698 | return (u8 *)l->items; | 707 | return (u8 *)l->items; |
diff --git a/fs/btrfs/debug-tree.c b/fs/btrfs/debug-tree.c deleted file mode 100644 index fd07969600c6..000000000000 --- a/fs/btrfs/debug-tree.c +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include "kerncompat.h" | ||
4 | #include "radix-tree.h" | ||
5 | #include "ctree.h" | ||
6 | #include "disk-io.h" | ||
7 | #include "print-tree.h" | ||
8 | #include "transaction.h" | ||
9 | |||
10 | int main(int ac, char **av) { | ||
11 | struct btrfs_super_block super; | ||
12 | struct btrfs_root *root; | ||
13 | |||
14 | if (ac != 2) { | ||
15 | fprintf(stderr, "usage: %s device\n", av[0]); | ||
16 | exit(1); | ||
17 | } | ||
18 | radix_tree_init(); | ||
19 | root = open_ctree(av[1], &super); | ||
20 | if (!root) { | ||
21 | fprintf(stderr, "unable to open %s\n", av[1]); | ||
22 | exit(1); | ||
23 | } | ||
24 | printf("fs tree\n"); | ||
25 | btrfs_print_tree(root, root->node); | ||
26 | printf("map tree\n"); | ||
27 | btrfs_print_tree(root->fs_info->extent_root, | ||
28 | root->fs_info->extent_root->node); | ||
29 | printf("inode tree\n"); | ||
30 | btrfs_print_tree(root->fs_info->inode_root, | ||
31 | root->fs_info->inode_root->node); | ||
32 | printf("root tree\n"); | ||
33 | btrfs_print_tree(root->fs_info->tree_root, | ||
34 | root->fs_info->tree_root->node); | ||
35 | printf("total blocks %Lu\n", btrfs_super_total_blocks(&super)); | ||
36 | printf("blocks used %Lu\n", btrfs_super_blocks_used(&super)); | ||
37 | return 0; | ||
38 | } | ||
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index 949c4e526798..4d8083d92fa0 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c | |||
@@ -1,7 +1,4 @@ | |||
1 | #include <stdio.h> | 1 | #include <linux/module.h> |
2 | #include <stdlib.h> | ||
3 | #include "kerncompat.h" | ||
4 | #include "radix-tree.h" | ||
5 | #include "ctree.h" | 2 | #include "ctree.h" |
6 | #include "disk-io.h" | 3 | #include "disk-io.h" |
7 | #include "hash.h" | 4 | #include "hash.h" |
@@ -21,7 +18,12 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root | |||
21 | key.objectid = dir; | 18 | key.objectid = dir; |
22 | key.flags = 0; | 19 | key.flags = 0; |
23 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); | 20 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); |
24 | ret = btrfs_name_hash(name, name_len, &key.offset); | 21 | if (name_len == 1 && *name == '.') |
22 | key.offset = 1; | ||
23 | else if (name_len == 2 && name[0] == '.' && name[1] == '.') | ||
24 | key.offset = 2; | ||
25 | else | ||
26 | ret = btrfs_name_hash(name, name_len, &key.offset); | ||
25 | BUG_ON(ret); | 27 | BUG_ON(ret); |
26 | btrfs_init_path(&path); | 28 | btrfs_init_path(&path); |
27 | data_size = sizeof(*dir_item) + name_len; | 29 | data_size = sizeof(*dir_item) + name_len; |
diff --git a/fs/btrfs/dir-test.c b/fs/btrfs/dir-test.c deleted file mode 100644 index b673982a1f3c..000000000000 --- a/fs/btrfs/dir-test.c +++ /dev/null | |||
@@ -1,494 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <signal.h> | ||
4 | #include <unistd.h> | ||
5 | #include "kerncompat.h" | ||
6 | #include "radix-tree.h" | ||
7 | #include "ctree.h" | ||
8 | #include "disk-io.h" | ||
9 | #include "print-tree.h" | ||
10 | #include "hash.h" | ||
11 | #include "transaction.h" | ||
12 | |||
13 | int keep_running = 1; | ||
14 | struct btrfs_super_block super; | ||
15 | static u64 dir_oid = 44556; | ||
16 | static u64 file_oid = 33778; | ||
17 | |||
18 | static int find_num(struct radix_tree_root *root, unsigned long *num_ret, | ||
19 | int exists) | ||
20 | { | ||
21 | unsigned long num = rand(); | ||
22 | unsigned long res[2]; | ||
23 | int ret; | ||
24 | |||
25 | again: | ||
26 | ret = radix_tree_gang_lookup(root, (void **)res, num, 2); | ||
27 | if (exists) { | ||
28 | if (ret == 0) | ||
29 | return -1; | ||
30 | num = res[0]; | ||
31 | } else if (ret != 0 && num == res[0]) { | ||
32 | num++; | ||
33 | if (ret > 1 && num == res[1]) { | ||
34 | num++; | ||
35 | goto again; | ||
36 | } | ||
37 | } | ||
38 | *num_ret = num; | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static void initial_inode_init(struct btrfs_root *root, | ||
43 | struct btrfs_inode_item *inode_item) | ||
44 | { | ||
45 | memset(inode_item, 0, sizeof(*inode_item)); | ||
46 | btrfs_set_inode_generation(inode_item, root->fs_info->generation); | ||
47 | } | ||
48 | |||
49 | static int ins_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
50 | struct radix_tree_root *radix) | ||
51 | { | ||
52 | int ret; | ||
53 | char buf[128]; | ||
54 | unsigned long oid; | ||
55 | u64 objectid; | ||
56 | struct btrfs_path path; | ||
57 | struct btrfs_key inode_map; | ||
58 | struct btrfs_inode_item inode_item; | ||
59 | |||
60 | find_num(radix, &oid, 0); | ||
61 | sprintf(buf, "str-%lu", oid); | ||
62 | |||
63 | ret = btrfs_find_free_objectid(trans, root, dir_oid + 1, &objectid); | ||
64 | if (ret) | ||
65 | goto error; | ||
66 | |||
67 | inode_map.objectid = objectid; | ||
68 | inode_map.flags = 0; | ||
69 | inode_map.offset = 0; | ||
70 | |||
71 | ret = btrfs_insert_inode_map(trans, root, objectid, &inode_map); | ||
72 | if (ret) | ||
73 | goto error; | ||
74 | |||
75 | initial_inode_init(root, &inode_item); | ||
76 | ret = btrfs_insert_inode(trans, root, objectid, &inode_item); | ||
77 | if (ret) | ||
78 | goto error; | ||
79 | ret = btrfs_insert_dir_item(trans, root, buf, strlen(buf), dir_oid, | ||
80 | objectid, 1); | ||
81 | if (ret) | ||
82 | goto error; | ||
83 | |||
84 | radix_tree_preload(GFP_KERNEL); | ||
85 | ret = radix_tree_insert(radix, oid, (void *)oid); | ||
86 | radix_tree_preload_end(); | ||
87 | if (ret) | ||
88 | goto error; | ||
89 | return ret; | ||
90 | error: | ||
91 | if (ret != -EEXIST) | ||
92 | goto fatal; | ||
93 | |||
94 | /* | ||
95 | * if we got an EEXIST, it may be due to hash collision, double | ||
96 | * check | ||
97 | */ | ||
98 | btrfs_init_path(&path); | ||
99 | ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf, | ||
100 | strlen(buf), 0); | ||
101 | if (ret) | ||
102 | goto fatal_release; | ||
103 | if (!btrfs_match_dir_item_name(root, &path, buf, strlen(buf))) { | ||
104 | struct btrfs_dir_item *di; | ||
105 | char *found; | ||
106 | u32 found_len; | ||
107 | u64 myhash; | ||
108 | u64 foundhash; | ||
109 | |||
110 | di = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0], | ||
111 | struct btrfs_dir_item); | ||
112 | found = (char *)(di + 1); | ||
113 | found_len = btrfs_dir_name_len(di); | ||
114 | btrfs_name_hash(buf, strlen(buf), &myhash); | ||
115 | btrfs_name_hash(found, found_len, &foundhash); | ||
116 | if (myhash != foundhash) | ||
117 | goto fatal_release; | ||
118 | btrfs_release_path(root, &path); | ||
119 | return 0; | ||
120 | } | ||
121 | fatal_release: | ||
122 | btrfs_release_path(root, &path); | ||
123 | fatal: | ||
124 | printf("failed to insert %lu ret %d\n", oid, ret); | ||
125 | return -1; | ||
126 | } | ||
127 | |||
128 | static int insert_dup(struct btrfs_trans_handle *trans, struct btrfs_root | ||
129 | *root, struct radix_tree_root *radix) | ||
130 | { | ||
131 | int ret; | ||
132 | char buf[128]; | ||
133 | unsigned long oid; | ||
134 | |||
135 | ret = find_num(radix, &oid, 1); | ||
136 | if (ret < 0) | ||
137 | return 0; | ||
138 | sprintf(buf, "str-%lu", oid); | ||
139 | |||
140 | ret = btrfs_insert_dir_item(trans, root, buf, strlen(buf), dir_oid, | ||
141 | file_oid, 1); | ||
142 | if (ret != -EEXIST) { | ||
143 | printf("insert on %s gave us %d\n", buf, ret); | ||
144 | return 1; | ||
145 | } | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int del_dir_item(struct btrfs_trans_handle *trans, | ||
150 | struct btrfs_root *root, | ||
151 | struct radix_tree_root *radix, | ||
152 | unsigned long radix_index, | ||
153 | struct btrfs_path *path) | ||
154 | { | ||
155 | int ret; | ||
156 | unsigned long *ptr; | ||
157 | u64 file_objectid; | ||
158 | struct btrfs_dir_item *di; | ||
159 | |||
160 | /* find the inode number of the file */ | ||
161 | di = btrfs_item_ptr(&path->nodes[0]->leaf, path->slots[0], | ||
162 | struct btrfs_dir_item); | ||
163 | file_objectid = btrfs_dir_objectid(di); | ||
164 | |||
165 | /* delete the directory item */ | ||
166 | ret = btrfs_del_item(trans, root, path); | ||
167 | if (ret) | ||
168 | goto out_release; | ||
169 | btrfs_release_path(root, path); | ||
170 | |||
171 | /* delete the inode */ | ||
172 | btrfs_init_path(path); | ||
173 | ret = btrfs_lookup_inode(trans, root, path, file_objectid, -1); | ||
174 | if (ret) | ||
175 | goto out_release; | ||
176 | ret = btrfs_del_item(trans, root, path); | ||
177 | if (ret) | ||
178 | goto out_release; | ||
179 | btrfs_release_path(root, path); | ||
180 | |||
181 | /* delete the inode mapping */ | ||
182 | btrfs_init_path(path); | ||
183 | ret = btrfs_lookup_inode_map(trans, root, path, file_objectid, -1); | ||
184 | if (ret) | ||
185 | goto out_release; | ||
186 | ret = btrfs_del_item(trans, root->fs_info->inode_root, path); | ||
187 | if (ret) | ||
188 | goto out_release; | ||
189 | |||
190 | if (root->fs_info->last_inode_alloc > file_objectid) | ||
191 | root->fs_info->last_inode_alloc = file_objectid; | ||
192 | btrfs_release_path(root, path); | ||
193 | ptr = radix_tree_delete(radix, radix_index); | ||
194 | if (!ptr) { | ||
195 | ret = -5555; | ||
196 | goto out; | ||
197 | } | ||
198 | return 0; | ||
199 | out_release: | ||
200 | btrfs_release_path(root, path); | ||
201 | out: | ||
202 | printf("failed to delete %lu %d\n", radix_index, ret); | ||
203 | return -1; | ||
204 | } | ||
205 | |||
206 | static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
207 | struct radix_tree_root *radix) | ||
208 | { | ||
209 | int ret; | ||
210 | char buf[128]; | ||
211 | unsigned long oid; | ||
212 | struct btrfs_path path; | ||
213 | |||
214 | ret = find_num(radix, &oid, 1); | ||
215 | if (ret < 0) | ||
216 | return 0; | ||
217 | sprintf(buf, "str-%lu", oid); | ||
218 | btrfs_init_path(&path); | ||
219 | ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf, | ||
220 | strlen(buf), -1); | ||
221 | if (ret) | ||
222 | goto out_release; | ||
223 | |||
224 | ret = del_dir_item(trans, root, radix, oid, &path); | ||
225 | if (ret) | ||
226 | goto out_release; | ||
227 | return ret; | ||
228 | out_release: | ||
229 | btrfs_release_path(root, &path); | ||
230 | printf("failed to delete %lu %d\n", oid, ret); | ||
231 | return -1; | ||
232 | } | ||
233 | |||
234 | static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root | ||
235 | *root, struct radix_tree_root *radix) | ||
236 | { | ||
237 | struct btrfs_path path; | ||
238 | char buf[128]; | ||
239 | int ret; | ||
240 | unsigned long oid; | ||
241 | u64 objectid; | ||
242 | struct btrfs_dir_item *di; | ||
243 | |||
244 | ret = find_num(radix, &oid, 1); | ||
245 | if (ret < 0) | ||
246 | return 0; | ||
247 | sprintf(buf, "str-%lu", oid); | ||
248 | btrfs_init_path(&path); | ||
249 | ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf, | ||
250 | strlen(buf), 0); | ||
251 | if (!ret) { | ||
252 | di = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0], | ||
253 | struct btrfs_dir_item); | ||
254 | objectid = btrfs_dir_objectid(di); | ||
255 | btrfs_release_path(root, &path); | ||
256 | btrfs_init_path(&path); | ||
257 | ret = btrfs_lookup_inode_map(trans, root, &path, objectid, 0); | ||
258 | } | ||
259 | btrfs_release_path(root, &path); | ||
260 | if (ret) { | ||
261 | printf("unable to find key %lu\n", oid); | ||
262 | return -1; | ||
263 | } | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static int lookup_enoent(struct btrfs_trans_handle *trans, struct btrfs_root | ||
268 | *root, struct radix_tree_root *radix) | ||
269 | { | ||
270 | struct btrfs_path path; | ||
271 | char buf[128]; | ||
272 | int ret; | ||
273 | unsigned long oid; | ||
274 | |||
275 | ret = find_num(radix, &oid, 0); | ||
276 | if (ret < 0) | ||
277 | return 0; | ||
278 | sprintf(buf, "str-%lu", oid); | ||
279 | btrfs_init_path(&path); | ||
280 | ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf, | ||
281 | strlen(buf), 0); | ||
282 | btrfs_release_path(root, &path); | ||
283 | if (!ret) { | ||
284 | printf("able to find key that should not exist %lu\n", oid); | ||
285 | return -1; | ||
286 | } | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root | ||
291 | *root, struct radix_tree_root *radix, int nr) | ||
292 | { | ||
293 | struct btrfs_path path; | ||
294 | struct btrfs_key key; | ||
295 | unsigned long found = 0; | ||
296 | u32 found_len; | ||
297 | int ret; | ||
298 | int slot; | ||
299 | int count = 0; | ||
300 | char buf[128]; | ||
301 | struct btrfs_dir_item *di; | ||
302 | |||
303 | key.offset = (u64)-1; | ||
304 | key.flags = 0; | ||
305 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); | ||
306 | key.objectid = dir_oid; | ||
307 | while(nr-- >= 0) { | ||
308 | btrfs_init_path(&path); | ||
309 | ret = btrfs_search_slot(trans, root, &key, &path, -1, 1); | ||
310 | if (ret < 0) { | ||
311 | btrfs_release_path(root, &path); | ||
312 | return ret; | ||
313 | } | ||
314 | if (ret != 0) { | ||
315 | if (path.slots[0] == 0) { | ||
316 | btrfs_release_path(root, &path); | ||
317 | break; | ||
318 | } | ||
319 | path.slots[0] -= 1; | ||
320 | } | ||
321 | slot = path.slots[0]; | ||
322 | di = btrfs_item_ptr(&path.nodes[0]->leaf, slot, | ||
323 | struct btrfs_dir_item); | ||
324 | found_len = btrfs_dir_name_len(di); | ||
325 | memcpy(buf, (char *)(di + 1), found_len); | ||
326 | BUG_ON(found_len > 128); | ||
327 | buf[found_len] = '\0'; | ||
328 | found = atoi(buf + 4); | ||
329 | ret = del_dir_item(trans, root, radix, found, &path); | ||
330 | count++; | ||
331 | if (ret) { | ||
332 | fprintf(stderr, | ||
333 | "failed to remove %lu from tree\n", | ||
334 | found); | ||
335 | return -1; | ||
336 | } | ||
337 | if (!keep_running) | ||
338 | break; | ||
339 | } | ||
340 | return 0; | ||
341 | fprintf(stderr, "failed to delete from the radix %lu\n", found); | ||
342 | return -1; | ||
343 | } | ||
344 | |||
345 | static int fill_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
346 | struct radix_tree_root *radix, int count) | ||
347 | { | ||
348 | int i; | ||
349 | int ret = 0; | ||
350 | for (i = 0; i < count; i++) { | ||
351 | ret = ins_one(trans, root, radix); | ||
352 | if (ret) { | ||
353 | fprintf(stderr, "fill failed\n"); | ||
354 | goto out; | ||
355 | } | ||
356 | if (i % 1000 == 0) { | ||
357 | ret = btrfs_commit_transaction(trans, root, &super); | ||
358 | if (ret) { | ||
359 | fprintf(stderr, "fill commit failed\n"); | ||
360 | return ret; | ||
361 | } | ||
362 | } | ||
363 | if (i && i % 10000 == 0) { | ||
364 | printf("bigfill %d\n", i); | ||
365 | } | ||
366 | if (!keep_running) | ||
367 | break; | ||
368 | } | ||
369 | out: | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | static int bulk_op(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
374 | struct radix_tree_root *radix) | ||
375 | { | ||
376 | int ret; | ||
377 | int nr = rand() % 5000; | ||
378 | static int run_nr = 0; | ||
379 | |||
380 | /* do the bulk op much less frequently */ | ||
381 | if (run_nr++ % 100) | ||
382 | return 0; | ||
383 | ret = empty_tree(trans, root, radix, nr); | ||
384 | if (ret) | ||
385 | return ret; | ||
386 | ret = fill_tree(trans, root, radix, nr); | ||
387 | if (ret) | ||
388 | return ret; | ||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | |||
393 | int (*ops[])(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct | ||
394 | radix_tree_root *radix) = | ||
395 | { ins_one, insert_dup, del_one, lookup_item, | ||
396 | lookup_enoent, bulk_op }; | ||
397 | |||
398 | void sigstopper(int ignored) | ||
399 | { | ||
400 | keep_running = 0; | ||
401 | fprintf(stderr, "caught exit signal, stopping\n"); | ||
402 | } | ||
403 | |||
404 | int print_usage(void) | ||
405 | { | ||
406 | printf("usage: tester [-ih] [-c count] [-f count]\n"); | ||
407 | printf("\t -c count -- iteration count after filling\n"); | ||
408 | printf("\t -f count -- run this many random inserts before starting\n"); | ||
409 | printf("\t -i -- only do initial fill\n"); | ||
410 | printf("\t -h -- this help text\n"); | ||
411 | exit(1); | ||
412 | } | ||
413 | int main(int ac, char **av) | ||
414 | { | ||
415 | RADIX_TREE(radix, GFP_KERNEL); | ||
416 | struct btrfs_root *root; | ||
417 | int i; | ||
418 | int ret; | ||
419 | int count; | ||
420 | int op; | ||
421 | int iterations = 20000; | ||
422 | int init_fill_count = 800000; | ||
423 | int err = 0; | ||
424 | int initial_only = 0; | ||
425 | struct btrfs_trans_handle *trans; | ||
426 | radix_tree_init(); | ||
427 | |||
428 | root = open_ctree("dbfile", &super); | ||
429 | trans = btrfs_start_transaction(root, 1); | ||
430 | |||
431 | signal(SIGTERM, sigstopper); | ||
432 | signal(SIGINT, sigstopper); | ||
433 | |||
434 | for (i = 1 ; i < ac ; i++) { | ||
435 | if (strcmp(av[i], "-i") == 0) { | ||
436 | initial_only = 1; | ||
437 | } else if (strcmp(av[i], "-c") == 0) { | ||
438 | iterations = atoi(av[i+1]); | ||
439 | i++; | ||
440 | } else if (strcmp(av[i], "-f") == 0) { | ||
441 | init_fill_count = atoi(av[i+1]); | ||
442 | i++; | ||
443 | } else { | ||
444 | print_usage(); | ||
445 | } | ||
446 | } | ||
447 | printf("initial fill\n"); | ||
448 | ret = fill_tree(trans, root, &radix, init_fill_count); | ||
449 | printf("starting run\n"); | ||
450 | if (ret) { | ||
451 | err = ret; | ||
452 | goto out; | ||
453 | } | ||
454 | if (initial_only == 1) { | ||
455 | goto out; | ||
456 | } | ||
457 | for (i = 0; i < iterations; i++) { | ||
458 | op = rand() % ARRAY_SIZE(ops); | ||
459 | count = rand() % 128; | ||
460 | if (i % 2000 == 0) { | ||
461 | printf("%d\n", i); | ||
462 | fflush(stdout); | ||
463 | } | ||
464 | if (i && i % 5000 == 0) { | ||
465 | printf("open & close, root level %d nritems %d\n", | ||
466 | btrfs_header_level(&root->node->node.header), | ||
467 | btrfs_header_nritems(&root->node->node.header)); | ||
468 | close_ctree(root, &super); | ||
469 | root = open_ctree("dbfile", &super); | ||
470 | } | ||
471 | while(count--) { | ||
472 | ret = ops[op](trans, root, &radix); | ||
473 | if (ret) { | ||
474 | fprintf(stderr, "op %d failed %d:%d\n", | ||
475 | op, i, iterations); | ||
476 | btrfs_print_tree(root, root->node); | ||
477 | fprintf(stderr, "op %d failed %d:%d\n", | ||
478 | op, i, iterations); | ||
479 | err = ret; | ||
480 | goto out; | ||
481 | } | ||
482 | if (ops[op] == bulk_op) | ||
483 | break; | ||
484 | if (keep_running == 0) { | ||
485 | err = 0; | ||
486 | goto out; | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | out: | ||
491 | close_ctree(root, &super); | ||
492 | return err; | ||
493 | } | ||
494 | |||
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 0322c55162cb..05637f9fd7c7 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -267,19 +267,24 @@ static int find_and_setup_root(struct btrfs_super_block *super, | |||
267 | 267 | ||
268 | struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) | 268 | struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) |
269 | { | 269 | { |
270 | int fp; | ||
271 | |||
272 | fp = open(filename, O_CREAT | O_RDWR, 0600); | ||
273 | if (fp < 0) { | ||
274 | return NULL; | ||
275 | } | ||
276 | return open_ctree_fd(fp, super); | ||
277 | } | ||
278 | |||
279 | struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super) | ||
280 | { | ||
270 | struct btrfs_root *root = malloc(sizeof(struct btrfs_root)); | 281 | struct btrfs_root *root = malloc(sizeof(struct btrfs_root)); |
271 | struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root)); | 282 | struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root)); |
272 | struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root)); | 283 | struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root)); |
273 | struct btrfs_root *inode_root = malloc(sizeof(struct btrfs_root)); | 284 | struct btrfs_root *inode_root = malloc(sizeof(struct btrfs_root)); |
274 | struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info)); | 285 | struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info)); |
275 | int fp; | ||
276 | int ret; | 286 | int ret; |
277 | 287 | ||
278 | fp = open(filename, O_CREAT | O_RDWR, 0600); | ||
279 | if (fp < 0) { | ||
280 | free(root); | ||
281 | return NULL; | ||
282 | } | ||
283 | INIT_RADIX_TREE(&fs_info->cache_radix, GFP_KERNEL); | 288 | INIT_RADIX_TREE(&fs_info->cache_radix, GFP_KERNEL); |
284 | INIT_RADIX_TREE(&fs_info->pinned_radix, GFP_KERNEL); | 289 | INIT_RADIX_TREE(&fs_info->pinned_radix, GFP_KERNEL); |
285 | INIT_LIST_HEAD(&fs_info->trans); | 290 | INIT_LIST_HEAD(&fs_info->trans); |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 24a9e77c8311..d888cf5c350b 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -24,6 +24,7 @@ int clean_tree_block(struct btrfs_trans_handle *trans, | |||
24 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct btrfs_root | 24 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct btrfs_root |
25 | *root, struct btrfs_super_block *s); | 25 | *root, struct btrfs_super_block *s); |
26 | struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *s); | 26 | struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *s); |
27 | struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super); | ||
27 | int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s); | 28 | int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s); |
28 | void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf); | 29 | void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf); |
29 | int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 30 | int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9bc4ad38876d..53a7550b5c1e 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -1,7 +1,5 @@ | |||
1 | #include <stdio.h> | 1 | #include <linux/module.h> |
2 | #include <stdlib.h> | 2 | #include <linux/radix-tree.h> |
3 | #include "kerncompat.h" | ||
4 | #include "radix-tree.h" | ||
5 | #include "ctree.h" | 3 | #include "ctree.h" |
6 | #include "disk-io.h" | 4 | #include "disk-io.h" |
7 | #include "print-tree.h" | 5 | #include "print-tree.h" |
@@ -183,9 +181,9 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
183 | btrfs_init_path(&path); | 181 | btrfs_init_path(&path); |
184 | ret = btrfs_search_slot(trans, extent_root, &key, &path, -1, 1); | 182 | ret = btrfs_search_slot(trans, extent_root, &key, &path, -1, 1); |
185 | if (ret) { | 183 | if (ret) { |
186 | printf("failed to find %Lu\n", key.objectid); | 184 | printk("failed to find %Lu\n", key.objectid); |
187 | btrfs_print_tree(extent_root, extent_root->node); | 185 | btrfs_print_tree(extent_root, extent_root->node); |
188 | printf("failed to find %Lu\n", key.objectid); | 186 | printk("failed to find %Lu\n", key.objectid); |
189 | BUG(); | 187 | BUG(); |
190 | } | 188 | } |
191 | ei = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0], | 189 | ei = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0], |
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 24cfd6d85240..8e1e5b4ccfaf 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -1,9 +1,5 @@ | |||
1 | #include <stdio.h> | 1 | #include <linux/module.h> |
2 | #include <stdlib.h> | ||
3 | #include "kerncompat.h" | ||
4 | #include "radix-tree.h" | ||
5 | #include "ctree.h" | 2 | #include "ctree.h" |
6 | #include "disk-io.h" | ||
7 | #include "transaction.h" | 3 | #include "transaction.h" |
8 | 4 | ||
9 | int btrfs_create_file(struct btrfs_trans_handle *trans, | 5 | int btrfs_create_file(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/hash.c b/fs/btrfs/hash.c index 92c37eece1f2..6c2a71a46c7d 100644 --- a/fs/btrfs/hash.c +++ b/fs/btrfs/hash.c | |||
@@ -10,7 +10,6 @@ | |||
10 | * License. | 10 | * License. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include "kerncompat.h" | ||
14 | #define DELTA 0x9E3779B9 | 13 | #define DELTA 0x9E3779B9 |
15 | 14 | ||
16 | static void TEA_transform(__u32 buf[2], __u32 const in[]) | 15 | static void TEA_transform(__u32 buf[2], __u32 const in[]) |
diff --git a/fs/btrfs/hasher.c b/fs/btrfs/hasher.c deleted file mode 100644 index 96702da4329c..000000000000 --- a/fs/btrfs/hasher.c +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <string.h> | ||
4 | #include "kerncompat.h" | ||
5 | #include "hash.h" | ||
6 | |||
7 | int main() { | ||
8 | u64 result; | ||
9 | int ret; | ||
10 | char line[255]; | ||
11 | char *p; | ||
12 | while(1) { | ||
13 | p = fgets(line, 255, stdin); | ||
14 | if (!p) | ||
15 | break; | ||
16 | if (strlen(line) == 0) | ||
17 | continue; | ||
18 | ret = btrfs_name_hash(line, strlen(line), &result); | ||
19 | BUG_ON(ret); | ||
20 | printf("hash returns %Lu\n", result); | ||
21 | } | ||
22 | return 0; | ||
23 | } | ||
diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c index 7caeb11e8756..8d8c26a6c1a0 100644 --- a/fs/btrfs/inode-item.c +++ b/fs/btrfs/inode-item.c | |||
@@ -1,7 +1,4 @@ | |||
1 | #include <stdio.h> | 1 | #include <linux/module.h> |
2 | #include <stdlib.h> | ||
3 | #include "kerncompat.h" | ||
4 | #include "radix-tree.h" | ||
5 | #include "ctree.h" | 2 | #include "ctree.h" |
6 | #include "disk-io.h" | 3 | #include "disk-io.h" |
7 | #include "transaction.h" | 4 | #include "transaction.h" |
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index f412b3392135..c7fda3bf7b21 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c | |||
@@ -1,7 +1,4 @@ | |||
1 | #include <stdio.h> | 1 | #include <linux/module.h> |
2 | #include <stdlib.h> | ||
3 | #include "kerncompat.h" | ||
4 | #include "radix-tree.h" | ||
5 | #include "ctree.h" | 2 | #include "ctree.h" |
6 | #include "disk-io.h" | 3 | #include "disk-io.h" |
7 | #include "transaction.h" | 4 | #include "transaction.h" |
diff --git a/fs/btrfs/kerncompat.h b/fs/btrfs/kerncompat.h deleted file mode 100644 index 105d3f584089..000000000000 --- a/fs/btrfs/kerncompat.h +++ /dev/null | |||
@@ -1,96 +0,0 @@ | |||
1 | #ifndef __KERNCOMPAT | ||
2 | #define __KERNCOMPAT | ||
3 | #define gfp_t int | ||
4 | #define get_cpu_var(p) (p) | ||
5 | #define __get_cpu_var(p) (p) | ||
6 | #define BITS_PER_LONG 64 | ||
7 | #define __GFP_BITS_SHIFT 20 | ||
8 | #define __GFP_BITS_MASK ((int)((1 << __GFP_BITS_SHIFT) - 1)) | ||
9 | #define GFP_KERNEL 0 | ||
10 | #define __read_mostly | ||
11 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
12 | #define PAGE_SHIFT 12 | ||
13 | #define ULONG_MAX (~0UL) | ||
14 | #define BUG() abort() | ||
15 | #ifdef __CHECKER__ | ||
16 | #define __force __attribute__((force)) | ||
17 | #define __bitwise__ __attribute__((bitwise)) | ||
18 | #else | ||
19 | #define __force | ||
20 | #define __bitwise__ | ||
21 | #endif | ||
22 | |||
23 | typedef unsigned int u32; | ||
24 | typedef u32 __u32; | ||
25 | typedef unsigned long long u64; | ||
26 | typedef unsigned char u8; | ||
27 | typedef unsigned short u16; | ||
28 | |||
29 | typedef unsigned long pgoff_t; | ||
30 | |||
31 | #include <stdio.h> | ||
32 | #include <stdlib.h> | ||
33 | #include <string.h> | ||
34 | |||
35 | struct vma_shared { int prio_tree_node; }; | ||
36 | struct vm_area_struct { | ||
37 | unsigned long vm_pgoff; | ||
38 | unsigned long vm_start; | ||
39 | unsigned long vm_end; | ||
40 | struct vma_shared shared; | ||
41 | }; | ||
42 | |||
43 | struct page { | ||
44 | unsigned long index; | ||
45 | }; | ||
46 | |||
47 | static inline void preempt_enable(void) { do {; } while(0);} | ||
48 | static inline void preempt_disable(void) { do {; } while(0);} | ||
49 | |||
50 | static inline void __set_bit(int bit, unsigned long *map) { | ||
51 | unsigned long *p = map + bit / BITS_PER_LONG; | ||
52 | bit = bit & (BITS_PER_LONG -1); | ||
53 | *p |= 1UL << bit; | ||
54 | } | ||
55 | |||
56 | static inline int test_bit(int bit, unsigned long *map) { | ||
57 | unsigned long *p = map + bit / BITS_PER_LONG; | ||
58 | bit = bit & (BITS_PER_LONG -1); | ||
59 | return *p & (1UL << bit) ? 1 : 0; | ||
60 | } | ||
61 | |||
62 | static inline void __clear_bit(int bit, unsigned long *map) { | ||
63 | unsigned long *p = map + bit / BITS_PER_LONG; | ||
64 | bit = bit & (BITS_PER_LONG -1); | ||
65 | *p &= ~(1UL << bit); | ||
66 | } | ||
67 | #define BUG_ON(c) do { if (c) abort(); } while (0) | ||
68 | |||
69 | #define container_of(ptr, type, member) ({ \ | ||
70 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | ||
71 | (type *)( (char *)__mptr - __builtin_offsetof(type,member) );}) | ||
72 | |||
73 | #define ENOMEM 5 | ||
74 | #define EEXIST 6 | ||
75 | |||
76 | #define __CHECK_ENDIAN__ | ||
77 | #ifdef __CHECK_ENDIAN__ | ||
78 | #define __bitwise __bitwise__ | ||
79 | #else | ||
80 | #define __bitwise | ||
81 | #endif | ||
82 | |||
83 | typedef u16 __bitwise __le16; | ||
84 | typedef u16 __bitwise __be16; | ||
85 | typedef u32 __bitwise __le32; | ||
86 | typedef u32 __bitwise __be32; | ||
87 | typedef u64 __bitwise __le64; | ||
88 | typedef u64 __bitwise __be64; | ||
89 | |||
90 | #define cpu_to_le64(x) ((__force __le64)(u64)(x)) | ||
91 | #define le64_to_cpu(x) ((__force u64)(__le64)(x)) | ||
92 | #define cpu_to_le32(x) ((__force __le32)(u32)(x)) | ||
93 | #define le32_to_cpu(x) ((__force u32)(__le32)(x)) | ||
94 | #define cpu_to_le16(x) ((__force __le16)(u16)(x)) | ||
95 | #define le16_to_cpu(x) ((__force u16)(__le16)(x)) | ||
96 | #endif | ||
diff --git a/fs/btrfs/list.h b/fs/btrfs/list.h deleted file mode 100644 index 1aafafb13370..000000000000 --- a/fs/btrfs/list.h +++ /dev/null | |||
@@ -1,418 +0,0 @@ | |||
1 | #ifndef _LINUX_LIST_H | ||
2 | #define _LINUX_LIST_H | ||
3 | |||
4 | #define LIST_POISON1 ((void *) 0x00100100) | ||
5 | #define LIST_POISON2 ((void *) 0x00200200) | ||
6 | |||
7 | /* | ||
8 | * Simple doubly linked list implementation. | ||
9 | * | ||
10 | * Some of the internal functions ("__xxx") are useful when | ||
11 | * manipulating whole lists rather than single entries, as | ||
12 | * sometimes we already know the next/prev entries and we can | ||
13 | * generate better code by using them directly rather than | ||
14 | * using the generic single-entry routines. | ||
15 | */ | ||
16 | |||
17 | struct list_head { | ||
18 | struct list_head *next, *prev; | ||
19 | }; | ||
20 | |||
21 | #define LIST_HEAD_INIT(name) { &(name), &(name) } | ||
22 | |||
23 | #define LIST_HEAD(name) \ | ||
24 | struct list_head name = LIST_HEAD_INIT(name) | ||
25 | |||
26 | static inline void INIT_LIST_HEAD(struct list_head *list) | ||
27 | { | ||
28 | list->next = list; | ||
29 | list->prev = list; | ||
30 | } | ||
31 | |||
32 | /* | ||
33 | * Insert a new entry between two known consecutive entries. | ||
34 | * | ||
35 | * This is only for internal list manipulation where we know | ||
36 | * the prev/next entries already! | ||
37 | */ | ||
38 | #ifndef CONFIG_DEBUG_LIST | ||
39 | static inline void __list_add(struct list_head *new, | ||
40 | struct list_head *prev, | ||
41 | struct list_head *next) | ||
42 | { | ||
43 | next->prev = new; | ||
44 | new->next = next; | ||
45 | new->prev = prev; | ||
46 | prev->next = new; | ||
47 | } | ||
48 | #else | ||
49 | extern void __list_add(struct list_head *new, | ||
50 | struct list_head *prev, | ||
51 | struct list_head *next); | ||
52 | #endif | ||
53 | |||
54 | /** | ||
55 | * list_add - add a new entry | ||
56 | * @new: new entry to be added | ||
57 | * @head: list head to add it after | ||
58 | * | ||
59 | * Insert a new entry after the specified head. | ||
60 | * This is good for implementing stacks. | ||
61 | */ | ||
62 | #ifndef CONFIG_DEBUG_LIST | ||
63 | static inline void list_add(struct list_head *new, struct list_head *head) | ||
64 | { | ||
65 | __list_add(new, head, head->next); | ||
66 | } | ||
67 | #else | ||
68 | extern void list_add(struct list_head *new, struct list_head *head); | ||
69 | #endif | ||
70 | |||
71 | |||
72 | /** | ||
73 | * list_add_tail - add a new entry | ||
74 | * @new: new entry to be added | ||
75 | * @head: list head to add it before | ||
76 | * | ||
77 | * Insert a new entry before the specified head. | ||
78 | * This is useful for implementing queues. | ||
79 | */ | ||
80 | static inline void list_add_tail(struct list_head *new, struct list_head *head) | ||
81 | { | ||
82 | __list_add(new, head->prev, head); | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Delete a list entry by making the prev/next entries | ||
87 | * point to each other. | ||
88 | * | ||
89 | * This is only for internal list manipulation where we know | ||
90 | * the prev/next entries already! | ||
91 | */ | ||
92 | static inline void __list_del(struct list_head * prev, struct list_head * next) | ||
93 | { | ||
94 | next->prev = prev; | ||
95 | prev->next = next; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * list_del - deletes entry from list. | ||
100 | * @entry: the element to delete from the list. | ||
101 | * Note: list_empty on entry does not return true after this, the entry is | ||
102 | * in an undefined state. | ||
103 | */ | ||
104 | #ifndef CONFIG_DEBUG_LIST | ||
105 | static inline void list_del(struct list_head *entry) | ||
106 | { | ||
107 | __list_del(entry->prev, entry->next); | ||
108 | entry->next = LIST_POISON1; | ||
109 | entry->prev = LIST_POISON2; | ||
110 | } | ||
111 | #else | ||
112 | extern void list_del(struct list_head *entry); | ||
113 | #endif | ||
114 | |||
115 | /** | ||
116 | * list_replace - replace old entry by new one | ||
117 | * @old : the element to be replaced | ||
118 | * @new : the new element to insert | ||
119 | * Note: if 'old' was empty, it will be overwritten. | ||
120 | */ | ||
121 | static inline void list_replace(struct list_head *old, | ||
122 | struct list_head *new) | ||
123 | { | ||
124 | new->next = old->next; | ||
125 | new->next->prev = new; | ||
126 | new->prev = old->prev; | ||
127 | new->prev->next = new; | ||
128 | } | ||
129 | |||
130 | static inline void list_replace_init(struct list_head *old, | ||
131 | struct list_head *new) | ||
132 | { | ||
133 | list_replace(old, new); | ||
134 | INIT_LIST_HEAD(old); | ||
135 | } | ||
136 | /** | ||
137 | * list_del_init - deletes entry from list and reinitialize it. | ||
138 | * @entry: the element to delete from the list. | ||
139 | */ | ||
140 | static inline void list_del_init(struct list_head *entry) | ||
141 | { | ||
142 | __list_del(entry->prev, entry->next); | ||
143 | INIT_LIST_HEAD(entry); | ||
144 | } | ||
145 | |||
146 | /** | ||
147 | * list_move - delete from one list and add as another's head | ||
148 | * @list: the entry to move | ||
149 | * @head: the head that will precede our entry | ||
150 | */ | ||
151 | static inline void list_move(struct list_head *list, struct list_head *head) | ||
152 | { | ||
153 | __list_del(list->prev, list->next); | ||
154 | list_add(list, head); | ||
155 | } | ||
156 | |||
157 | /** | ||
158 | * list_move_tail - delete from one list and add as another's tail | ||
159 | * @list: the entry to move | ||
160 | * @head: the head that will follow our entry | ||
161 | */ | ||
162 | static inline void list_move_tail(struct list_head *list, | ||
163 | struct list_head *head) | ||
164 | { | ||
165 | __list_del(list->prev, list->next); | ||
166 | list_add_tail(list, head); | ||
167 | } | ||
168 | |||
169 | /** | ||
170 | * list_is_last - tests whether @list is the last entry in list @head | ||
171 | * @list: the entry to test | ||
172 | * @head: the head of the list | ||
173 | */ | ||
174 | static inline int list_is_last(const struct list_head *list, | ||
175 | const struct list_head *head) | ||
176 | { | ||
177 | return list->next == head; | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * list_empty - tests whether a list is empty | ||
182 | * @head: the list to test. | ||
183 | */ | ||
184 | static inline int list_empty(const struct list_head *head) | ||
185 | { | ||
186 | return head->next == head; | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * list_empty_careful - tests whether a list is empty and not being modified | ||
191 | * @head: the list to test | ||
192 | * | ||
193 | * Description: | ||
194 | * tests whether a list is empty _and_ checks that no other CPU might be | ||
195 | * in the process of modifying either member (next or prev) | ||
196 | * | ||
197 | * NOTE: using list_empty_careful() without synchronization | ||
198 | * can only be safe if the only activity that can happen | ||
199 | * to the list entry is list_del_init(). Eg. it cannot be used | ||
200 | * if another CPU could re-list_add() it. | ||
201 | */ | ||
202 | static inline int list_empty_careful(const struct list_head *head) | ||
203 | { | ||
204 | struct list_head *next = head->next; | ||
205 | return (next == head) && (next == head->prev); | ||
206 | } | ||
207 | |||
208 | static inline void __list_splice(struct list_head *list, | ||
209 | struct list_head *head) | ||
210 | { | ||
211 | struct list_head *first = list->next; | ||
212 | struct list_head *last = list->prev; | ||
213 | struct list_head *at = head->next; | ||
214 | |||
215 | first->prev = head; | ||
216 | head->next = first; | ||
217 | |||
218 | last->next = at; | ||
219 | at->prev = last; | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * list_splice - join two lists | ||
224 | * @list: the new list to add. | ||
225 | * @head: the place to add it in the first list. | ||
226 | */ | ||
227 | static inline void list_splice(struct list_head *list, struct list_head *head) | ||
228 | { | ||
229 | if (!list_empty(list)) | ||
230 | __list_splice(list, head); | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * list_splice_init - join two lists and reinitialise the emptied list. | ||
235 | * @list: the new list to add. | ||
236 | * @head: the place to add it in the first list. | ||
237 | * | ||
238 | * The list at @list is reinitialised | ||
239 | */ | ||
240 | static inline void list_splice_init(struct list_head *list, | ||
241 | struct list_head *head) | ||
242 | { | ||
243 | if (!list_empty(list)) { | ||
244 | __list_splice(list, head); | ||
245 | INIT_LIST_HEAD(list); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | /** | ||
250 | * list_entry - get the struct for this entry | ||
251 | * @ptr: the &struct list_head pointer. | ||
252 | * @type: the type of the struct this is embedded in. | ||
253 | * @member: the name of the list_struct within the struct. | ||
254 | */ | ||
255 | #define list_entry(ptr, type, member) \ | ||
256 | container_of(ptr, type, member) | ||
257 | |||
258 | /** | ||
259 | * list_for_each - iterate over a list | ||
260 | * @pos: the &struct list_head to use as a loop cursor. | ||
261 | * @head: the head for your list. | ||
262 | */ | ||
263 | #define list_for_each(pos, head) \ | ||
264 | for (pos = (head)->next; prefetch(pos->next), pos != (head); \ | ||
265 | pos = pos->next) | ||
266 | |||
267 | /** | ||
268 | * __list_for_each - iterate over a list | ||
269 | * @pos: the &struct list_head to use as a loop cursor. | ||
270 | * @head: the head for your list. | ||
271 | * | ||
272 | * This variant differs from list_for_each() in that it's the | ||
273 | * simplest possible list iteration code, no prefetching is done. | ||
274 | * Use this for code that knows the list to be very short (empty | ||
275 | * or 1 entry) most of the time. | ||
276 | */ | ||
277 | #define __list_for_each(pos, head) \ | ||
278 | for (pos = (head)->next; pos != (head); pos = pos->next) | ||
279 | |||
280 | /** | ||
281 | * list_for_each_prev - iterate over a list backwards | ||
282 | * @pos: the &struct list_head to use as a loop cursor. | ||
283 | * @head: the head for your list. | ||
284 | */ | ||
285 | #define list_for_each_prev(pos, head) \ | ||
286 | for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ | ||
287 | pos = pos->prev) | ||
288 | |||
289 | /** | ||
290 | * list_for_each_safe - iterate over a list safe against removal of list entry | ||
291 | * @pos: the &struct list_head to use as a loop cursor. | ||
292 | * @n: another &struct list_head to use as temporary storage | ||
293 | * @head: the head for your list. | ||
294 | */ | ||
295 | #define list_for_each_safe(pos, n, head) \ | ||
296 | for (pos = (head)->next, n = pos->next; pos != (head); \ | ||
297 | pos = n, n = pos->next) | ||
298 | |||
299 | /** | ||
300 | * list_for_each_entry - iterate over list of given type | ||
301 | * @pos: the type * to use as a loop cursor. | ||
302 | * @head: the head for your list. | ||
303 | * @member: the name of the list_struct within the struct. | ||
304 | */ | ||
305 | #define list_for_each_entry(pos, head, member) \ | ||
306 | for (pos = list_entry((head)->next, typeof(*pos), member); \ | ||
307 | prefetch(pos->member.next), &pos->member != (head); \ | ||
308 | pos = list_entry(pos->member.next, typeof(*pos), member)) | ||
309 | |||
310 | /** | ||
311 | * list_for_each_entry_reverse - iterate backwards over list of given type. | ||
312 | * @pos: the type * to use as a loop cursor. | ||
313 | * @head: the head for your list. | ||
314 | * @member: the name of the list_struct within the struct. | ||
315 | */ | ||
316 | #define list_for_each_entry_reverse(pos, head, member) \ | ||
317 | for (pos = list_entry((head)->prev, typeof(*pos), member); \ | ||
318 | prefetch(pos->member.prev), &pos->member != (head); \ | ||
319 | pos = list_entry(pos->member.prev, typeof(*pos), member)) | ||
320 | |||
321 | /** | ||
322 | * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue | ||
323 | * @pos: the type * to use as a start point | ||
324 | * @head: the head of the list | ||
325 | * @member: the name of the list_struct within the struct. | ||
326 | * | ||
327 | * Prepares a pos entry for use as a start point in list_for_each_entry_continue. | ||
328 | */ | ||
329 | #define list_prepare_entry(pos, head, member) \ | ||
330 | ((pos) ? : list_entry(head, typeof(*pos), member)) | ||
331 | |||
332 | /** | ||
333 | * list_for_each_entry_continue - continue iteration over list of given type | ||
334 | * @pos: the type * to use as a loop cursor. | ||
335 | * @head: the head for your list. | ||
336 | * @member: the name of the list_struct within the struct. | ||
337 | * | ||
338 | * Continue to iterate over list of given type, continuing after | ||
339 | * the current position. | ||
340 | */ | ||
341 | #define list_for_each_entry_continue(pos, head, member) \ | ||
342 | for (pos = list_entry(pos->member.next, typeof(*pos), member); \ | ||
343 | prefetch(pos->member.next), &pos->member != (head); \ | ||
344 | pos = list_entry(pos->member.next, typeof(*pos), member)) | ||
345 | |||
346 | /** | ||
347 | * list_for_each_entry_from - iterate over list of given type from the current point | ||
348 | * @pos: the type * to use as a loop cursor. | ||
349 | * @head: the head for your list. | ||
350 | * @member: the name of the list_struct within the struct. | ||
351 | * | ||
352 | * Iterate over list of given type, continuing from current position. | ||
353 | */ | ||
354 | #define list_for_each_entry_from(pos, head, member) \ | ||
355 | for (; prefetch(pos->member.next), &pos->member != (head); \ | ||
356 | pos = list_entry(pos->member.next, typeof(*pos), member)) | ||
357 | |||
358 | /** | ||
359 | * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry | ||
360 | * @pos: the type * to use as a loop cursor. | ||
361 | * @n: another type * to use as temporary storage | ||
362 | * @head: the head for your list. | ||
363 | * @member: the name of the list_struct within the struct. | ||
364 | */ | ||
365 | #define list_for_each_entry_safe(pos, n, head, member) \ | ||
366 | for (pos = list_entry((head)->next, typeof(*pos), member), \ | ||
367 | n = list_entry(pos->member.next, typeof(*pos), member); \ | ||
368 | &pos->member != (head); \ | ||
369 | pos = n, n = list_entry(n->member.next, typeof(*n), member)) | ||
370 | |||
371 | /** | ||
372 | * list_for_each_entry_safe_continue | ||
373 | * @pos: the type * to use as a loop cursor. | ||
374 | * @n: another type * to use as temporary storage | ||
375 | * @head: the head for your list. | ||
376 | * @member: the name of the list_struct within the struct. | ||
377 | * | ||
378 | * Iterate over list of given type, continuing after current point, | ||
379 | * safe against removal of list entry. | ||
380 | */ | ||
381 | #define list_for_each_entry_safe_continue(pos, n, head, member) \ | ||
382 | for (pos = list_entry(pos->member.next, typeof(*pos), member), \ | ||
383 | n = list_entry(pos->member.next, typeof(*pos), member); \ | ||
384 | &pos->member != (head); \ | ||
385 | pos = n, n = list_entry(n->member.next, typeof(*n), member)) | ||
386 | |||
387 | /** | ||
388 | * list_for_each_entry_safe_from | ||
389 | * @pos: the type * to use as a loop cursor. | ||
390 | * @n: another type * to use as temporary storage | ||
391 | * @head: the head for your list. | ||
392 | * @member: the name of the list_struct within the struct. | ||
393 | * | ||
394 | * Iterate over list of given type from current point, safe against | ||
395 | * removal of list entry. | ||
396 | */ | ||
397 | #define list_for_each_entry_safe_from(pos, n, head, member) \ | ||
398 | for (n = list_entry(pos->member.next, typeof(*pos), member); \ | ||
399 | &pos->member != (head); \ | ||
400 | pos = n, n = list_entry(n->member.next, typeof(*n), member)) | ||
401 | |||
402 | /** | ||
403 | * list_for_each_entry_safe_reverse | ||
404 | * @pos: the type * to use as a loop cursor. | ||
405 | * @n: another type * to use as temporary storage | ||
406 | * @head: the head for your list. | ||
407 | * @member: the name of the list_struct within the struct. | ||
408 | * | ||
409 | * Iterate backwards over list of given type, safe against removal | ||
410 | * of list entry. | ||
411 | */ | ||
412 | #define list_for_each_entry_safe_reverse(pos, n, head, member) \ | ||
413 | for (pos = list_entry((head)->prev, typeof(*pos), member), \ | ||
414 | n = list_entry(pos->member.prev, typeof(*pos), member); \ | ||
415 | &pos->member != (head); \ | ||
416 | pos = n, n = list_entry(n->member.prev, typeof(*n), member)) | ||
417 | |||
418 | #endif | ||
diff --git a/fs/btrfs/mkfs.c b/fs/btrfs/mkfs.c deleted file mode 100644 index f7efc8a5fb1a..000000000000 --- a/fs/btrfs/mkfs.c +++ /dev/null | |||
@@ -1,255 +0,0 @@ | |||
1 | #define _XOPEN_SOURCE 500 | ||
2 | #ifndef __CHECKER__ | ||
3 | #include <sys/ioctl.h> | ||
4 | #include <sys/mount.h> | ||
5 | #endif | ||
6 | #include <stdio.h> | ||
7 | #include <stdlib.h> | ||
8 | #include <sys/types.h> | ||
9 | #include <sys/stat.h> | ||
10 | #include <fcntl.h> | ||
11 | #include <unistd.h> | ||
12 | #include "kerncompat.h" | ||
13 | #include "radix-tree.h" | ||
14 | #include "ctree.h" | ||
15 | #include "disk-io.h" | ||
16 | |||
17 | #ifdef __CHECKER__ | ||
18 | #define BLKGETSIZE64 0 | ||
19 | static inline int ioctl(int fd, int define, u64 *size) { return 0; } | ||
20 | #endif | ||
21 | |||
22 | #if 0 | ||
23 | #if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64) | ||
24 | # define BLKGETSIZE64 _IOR(0x12, 114, __u64) | ||
25 | #endif | ||
26 | #endif | ||
27 | |||
28 | int mkfs(int fd, u64 num_blocks, u32 blocksize) | ||
29 | { | ||
30 | struct btrfs_super_block super; | ||
31 | struct btrfs_leaf *empty_leaf; | ||
32 | struct btrfs_root_item root_item; | ||
33 | struct btrfs_item item; | ||
34 | struct btrfs_extent_item extent_item; | ||
35 | char *block; | ||
36 | int ret; | ||
37 | u32 itemoff; | ||
38 | u32 start_block = BTRFS_SUPER_INFO_OFFSET / blocksize; | ||
39 | |||
40 | btrfs_set_super_blocknr(&super, start_block); | ||
41 | btrfs_set_super_root(&super, start_block + 1); | ||
42 | strcpy((char *)(&super.magic), BTRFS_MAGIC); | ||
43 | btrfs_set_super_blocksize(&super, blocksize); | ||
44 | btrfs_set_super_total_blocks(&super, num_blocks); | ||
45 | btrfs_set_super_blocks_used(&super, start_block + 5); | ||
46 | |||
47 | block = malloc(blocksize); | ||
48 | memset(block, 0, blocksize); | ||
49 | BUG_ON(sizeof(super) > blocksize); | ||
50 | memcpy(block, &super, sizeof(super)); | ||
51 | ret = pwrite(fd, block, blocksize, BTRFS_SUPER_INFO_OFFSET); | ||
52 | BUG_ON(ret != blocksize); | ||
53 | |||
54 | /* create the tree of root objects */ | ||
55 | empty_leaf = malloc(blocksize); | ||
56 | memset(empty_leaf, 0, blocksize); | ||
57 | btrfs_set_header_parentid(&empty_leaf->header, | ||
58 | BTRFS_ROOT_TREE_OBJECTID); | ||
59 | btrfs_set_header_blocknr(&empty_leaf->header, start_block + 1); | ||
60 | btrfs_set_header_nritems(&empty_leaf->header, 3); | ||
61 | |||
62 | /* create the items for the root tree */ | ||
63 | btrfs_set_root_blocknr(&root_item, start_block + 2); | ||
64 | btrfs_set_root_refs(&root_item, 1); | ||
65 | itemoff = __BTRFS_LEAF_DATA_SIZE(blocksize) - sizeof(root_item); | ||
66 | btrfs_set_item_offset(&item, itemoff); | ||
67 | btrfs_set_item_size(&item, sizeof(root_item)); | ||
68 | btrfs_set_disk_key_objectid(&item.key, BTRFS_EXTENT_TREE_OBJECTID); | ||
69 | btrfs_set_disk_key_offset(&item.key, 0); | ||
70 | btrfs_set_disk_key_flags(&item.key, 0); | ||
71 | btrfs_set_disk_key_type(&item.key, BTRFS_ROOT_ITEM_KEY); | ||
72 | memcpy(empty_leaf->items, &item, sizeof(item)); | ||
73 | memcpy(btrfs_leaf_data(empty_leaf) + itemoff, | ||
74 | &root_item, sizeof(root_item)); | ||
75 | |||
76 | btrfs_set_root_blocknr(&root_item, start_block + 3); | ||
77 | itemoff = itemoff - sizeof(root_item); | ||
78 | btrfs_set_item_offset(&item, itemoff); | ||
79 | btrfs_set_disk_key_objectid(&item.key, BTRFS_INODE_MAP_OBJECTID); | ||
80 | memcpy(empty_leaf->items + 1, &item, sizeof(item)); | ||
81 | memcpy(btrfs_leaf_data(empty_leaf) + itemoff, | ||
82 | &root_item, sizeof(root_item)); | ||
83 | |||
84 | btrfs_set_root_blocknr(&root_item, start_block + 4); | ||
85 | itemoff = itemoff - sizeof(root_item); | ||
86 | btrfs_set_item_offset(&item, itemoff); | ||
87 | btrfs_set_disk_key_objectid(&item.key, BTRFS_FS_TREE_OBJECTID); | ||
88 | memcpy(empty_leaf->items + 2, &item, sizeof(item)); | ||
89 | memcpy(btrfs_leaf_data(empty_leaf) + itemoff, | ||
90 | &root_item, sizeof(root_item)); | ||
91 | ret = pwrite(fd, empty_leaf, blocksize, (start_block + 1) * blocksize); | ||
92 | |||
93 | /* create the items for the extent tree */ | ||
94 | btrfs_set_header_parentid(&empty_leaf->header, | ||
95 | BTRFS_EXTENT_TREE_OBJECTID); | ||
96 | btrfs_set_header_blocknr(&empty_leaf->header, start_block + 2); | ||
97 | btrfs_set_header_nritems(&empty_leaf->header, 5); | ||
98 | |||
99 | /* item1, reserve blocks 0-16 */ | ||
100 | btrfs_set_disk_key_objectid(&item.key, 0); | ||
101 | btrfs_set_disk_key_offset(&item.key, start_block + 1); | ||
102 | btrfs_set_disk_key_flags(&item.key, 0); | ||
103 | btrfs_set_disk_key_type(&item.key, BTRFS_EXTENT_ITEM_KEY); | ||
104 | itemoff = __BTRFS_LEAF_DATA_SIZE(blocksize) - | ||
105 | sizeof(struct btrfs_extent_item); | ||
106 | btrfs_set_item_offset(&item, itemoff); | ||
107 | btrfs_set_item_size(&item, sizeof(struct btrfs_extent_item)); | ||
108 | btrfs_set_extent_refs(&extent_item, 1); | ||
109 | btrfs_set_extent_owner(&extent_item, 0); | ||
110 | memcpy(empty_leaf->items, &item, sizeof(item)); | ||
111 | memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item), | ||
112 | &extent_item, btrfs_item_size(&item)); | ||
113 | |||
114 | /* item2, give block 17 to the root */ | ||
115 | btrfs_set_disk_key_objectid(&item.key, start_block + 1); | ||
116 | btrfs_set_disk_key_offset(&item.key, 1); | ||
117 | itemoff = itemoff - sizeof(struct btrfs_extent_item); | ||
118 | btrfs_set_item_offset(&item, itemoff); | ||
119 | btrfs_set_extent_owner(&extent_item, BTRFS_ROOT_TREE_OBJECTID); | ||
120 | memcpy(empty_leaf->items + 1, &item, sizeof(item)); | ||
121 | memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item), | ||
122 | &extent_item, btrfs_item_size(&item)); | ||
123 | |||
124 | /* item3, give block 18 to the extent root */ | ||
125 | btrfs_set_disk_key_objectid(&item.key, start_block + 2); | ||
126 | btrfs_set_disk_key_offset(&item.key, 1); | ||
127 | itemoff = itemoff - sizeof(struct btrfs_extent_item); | ||
128 | btrfs_set_item_offset(&item, itemoff); | ||
129 | btrfs_set_extent_owner(&extent_item, BTRFS_EXTENT_TREE_OBJECTID); | ||
130 | memcpy(empty_leaf->items + 2, &item, sizeof(item)); | ||
131 | memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item), | ||
132 | &extent_item, btrfs_item_size(&item)); | ||
133 | |||
134 | /* item4, give block 19 to the inode map */ | ||
135 | btrfs_set_disk_key_objectid(&item.key, start_block + 3); | ||
136 | btrfs_set_disk_key_offset(&item.key, 1); | ||
137 | itemoff = itemoff - sizeof(struct btrfs_extent_item); | ||
138 | btrfs_set_item_offset(&item, itemoff); | ||
139 | btrfs_set_extent_owner(&extent_item, BTRFS_INODE_MAP_OBJECTID); | ||
140 | memcpy(empty_leaf->items + 3, &item, sizeof(item)); | ||
141 | memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item), | ||
142 | &extent_item, btrfs_item_size(&item)); | ||
143 | ret = pwrite(fd, empty_leaf, blocksize, (start_block + 2) * blocksize); | ||
144 | if (ret != blocksize) | ||
145 | return -1; | ||
146 | |||
147 | /* item5, give block 20 to the FS root */ | ||
148 | btrfs_set_disk_key_objectid(&item.key, start_block + 4); | ||
149 | btrfs_set_disk_key_offset(&item.key, 1); | ||
150 | itemoff = itemoff - sizeof(struct btrfs_extent_item); | ||
151 | btrfs_set_item_offset(&item, itemoff); | ||
152 | btrfs_set_extent_owner(&extent_item, BTRFS_FS_TREE_OBJECTID); | ||
153 | memcpy(empty_leaf->items + 4, &item, sizeof(item)); | ||
154 | memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item), | ||
155 | &extent_item, btrfs_item_size(&item)); | ||
156 | ret = pwrite(fd, empty_leaf, blocksize, (start_block + 2) * blocksize); | ||
157 | if (ret != blocksize) | ||
158 | return -1; | ||
159 | |||
160 | /* create the inode map */ | ||
161 | btrfs_set_header_parentid(&empty_leaf->header, | ||
162 | BTRFS_INODE_MAP_OBJECTID); | ||
163 | btrfs_set_header_blocknr(&empty_leaf->header, start_block + 3); | ||
164 | btrfs_set_header_nritems(&empty_leaf->header, 0); | ||
165 | ret = pwrite(fd, empty_leaf, blocksize, (start_block + 3) * blocksize); | ||
166 | if (ret != blocksize) | ||
167 | return -1; | ||
168 | |||
169 | /* finally create the FS root */ | ||
170 | btrfs_set_header_parentid(&empty_leaf->header, BTRFS_FS_TREE_OBJECTID); | ||
171 | btrfs_set_header_blocknr(&empty_leaf->header, start_block + 4); | ||
172 | btrfs_set_header_nritems(&empty_leaf->header, 0); | ||
173 | ret = pwrite(fd, empty_leaf, blocksize, (start_block + 4) * blocksize); | ||
174 | if (ret != blocksize) | ||
175 | return -1; | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | u64 device_size(int fd, struct stat *st) | ||
180 | { | ||
181 | u64 size; | ||
182 | if (S_ISREG(st->st_mode)) { | ||
183 | return st->st_size; | ||
184 | } | ||
185 | if (!S_ISBLK(st->st_mode)) { | ||
186 | return 0; | ||
187 | } | ||
188 | if (ioctl(fd, BLKGETSIZE64, &size) >= 0) { | ||
189 | return size; | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | int main(int ac, char **av) | ||
195 | { | ||
196 | char *file; | ||
197 | u64 block_count = 0; | ||
198 | int fd; | ||
199 | struct stat st; | ||
200 | int ret; | ||
201 | int i; | ||
202 | char *buf = malloc(4096); | ||
203 | if (ac >= 2) { | ||
204 | file = av[1]; | ||
205 | if (ac == 3) { | ||
206 | block_count = atoi(av[2]); | ||
207 | if (!block_count) { | ||
208 | fprintf(stderr, "error finding block count\n"); | ||
209 | exit(1); | ||
210 | } | ||
211 | } | ||
212 | } else { | ||
213 | fprintf(stderr, "usage: mkfs.btrfs file [block count]\n"); | ||
214 | exit(1); | ||
215 | } | ||
216 | fd = open(file, O_RDWR); | ||
217 | if (fd < 0) { | ||
218 | fprintf(stderr, "unable to open %s\n", file); | ||
219 | exit(1); | ||
220 | } | ||
221 | ret = fstat(fd, &st); | ||
222 | if (ret < 0) { | ||
223 | fprintf(stderr, "unable to stat %s\n", file); | ||
224 | exit(1); | ||
225 | } | ||
226 | if (block_count == 0) { | ||
227 | block_count = device_size(fd, &st); | ||
228 | if (block_count == 0) { | ||
229 | fprintf(stderr, "unable to find %s size\n", file); | ||
230 | exit(1); | ||
231 | } | ||
232 | } | ||
233 | block_count /= 4096; | ||
234 | if (block_count < 256) { | ||
235 | fprintf(stderr, "device %s is too small\n", file); | ||
236 | exit(1); | ||
237 | } | ||
238 | memset(buf, 0, 4096); | ||
239 | for(i = 0; i < 6; i++) { | ||
240 | ret = write(fd, buf, 4096); | ||
241 | if (ret != 4096) { | ||
242 | fprintf(stderr, "unable to zero fill device\n"); | ||
243 | exit(1); | ||
244 | } | ||
245 | } | ||
246 | ret = mkfs(fd, block_count, 4096); | ||
247 | if (ret) { | ||
248 | fprintf(stderr, "error during mkfs %d\n", ret); | ||
249 | exit(1); | ||
250 | } | ||
251 | printf("fs created on %s blocksize %d blocks %Lu\n", | ||
252 | file, 4096, block_count); | ||
253 | return 0; | ||
254 | } | ||
255 | |||
diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index f53b99da12f3..aa2d3fac8804 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c | |||
@@ -1,7 +1,4 @@ | |||
1 | #include <stdio.h> | 1 | #include <linux/module.h> |
2 | #include <stdlib.h> | ||
3 | #include "kerncompat.h" | ||
4 | #include "radix-tree.h" | ||
5 | #include "ctree.h" | 2 | #include "ctree.h" |
6 | #include "disk-io.h" | 3 | #include "disk-io.h" |
7 | 4 | ||
@@ -17,14 +14,14 @@ void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l) | |||
17 | struct btrfs_inode_item *ii; | 14 | struct btrfs_inode_item *ii; |
18 | u32 type; | 15 | u32 type; |
19 | 16 | ||
20 | printf("leaf %Lu total ptrs %d free space %d\n", | 17 | printk("leaf %Lu total ptrs %d free space %d\n", |
21 | btrfs_header_blocknr(&l->header), nr, | 18 | btrfs_header_blocknr(&l->header), nr, |
22 | btrfs_leaf_free_space(root, l)); | 19 | btrfs_leaf_free_space(root, l)); |
23 | fflush(stdout); | 20 | fflush(stdout); |
24 | for (i = 0 ; i < nr ; i++) { | 21 | for (i = 0 ; i < nr ; i++) { |
25 | item = l->items + i; | 22 | item = l->items + i; |
26 | type = btrfs_disk_key_type(&item->key); | 23 | type = btrfs_disk_key_type(&item->key); |
27 | printf("\titem %d key (%Lu %u %Lu) itemoff %d itemsize %d\n", | 24 | printk("\titem %d key (%Lu %u %Lu) itemoff %d itemsize %d\n", |
28 | i, | 25 | i, |
29 | btrfs_disk_key_objectid(&item->key), | 26 | btrfs_disk_key_objectid(&item->key), |
30 | btrfs_disk_key_flags(&item->key), | 27 | btrfs_disk_key_flags(&item->key), |
@@ -34,38 +31,39 @@ void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l) | |||
34 | switch (type) { | 31 | switch (type) { |
35 | case BTRFS_INODE_ITEM_KEY: | 32 | case BTRFS_INODE_ITEM_KEY: |
36 | ii = btrfs_item_ptr(l, i, struct btrfs_inode_item); | 33 | ii = btrfs_item_ptr(l, i, struct btrfs_inode_item); |
37 | printf("\t\tinode generation %Lu size %Lu\n", | 34 | printk("\t\tinode generation %Lu size %Lu mode %o\n", |
38 | btrfs_inode_generation(ii), | 35 | btrfs_inode_generation(ii), |
39 | btrfs_inode_size(ii)); | 36 | btrfs_inode_size(ii), |
37 | btrfs_inode_mode(ii)); | ||
40 | break; | 38 | break; |
41 | case BTRFS_DIR_ITEM_KEY: | 39 | case BTRFS_DIR_ITEM_KEY: |
42 | di = btrfs_item_ptr(l, i, struct btrfs_dir_item); | 40 | di = btrfs_item_ptr(l, i, struct btrfs_dir_item); |
43 | printf("\t\tdir oid %Lu flags %u type %u\n", | 41 | printk("\t\tdir oid %Lu flags %u type %u\n", |
44 | btrfs_dir_objectid(di), | 42 | btrfs_dir_objectid(di), |
45 | btrfs_dir_flags(di), | 43 | btrfs_dir_flags(di), |
46 | btrfs_dir_type(di)); | 44 | btrfs_dir_type(di)); |
47 | printf("\t\tname %.*s\n", | 45 | printk("\t\tname %.*s\n", |
48 | btrfs_dir_name_len(di),(char *)(di + 1)); | 46 | btrfs_dir_name_len(di),(char *)(di + 1)); |
49 | break; | 47 | break; |
50 | case BTRFS_ROOT_ITEM_KEY: | 48 | case BTRFS_ROOT_ITEM_KEY: |
51 | ri = btrfs_item_ptr(l, i, struct btrfs_root_item); | 49 | ri = btrfs_item_ptr(l, i, struct btrfs_root_item); |
52 | printf("\t\troot data blocknr %Lu refs %u\n", | 50 | printk("\t\troot data blocknr %Lu refs %u\n", |
53 | btrfs_root_blocknr(ri), btrfs_root_refs(ri)); | 51 | btrfs_root_blocknr(ri), btrfs_root_refs(ri)); |
54 | break; | 52 | break; |
55 | case BTRFS_EXTENT_ITEM_KEY: | 53 | case BTRFS_EXTENT_ITEM_KEY: |
56 | ei = btrfs_item_ptr(l, i, struct btrfs_extent_item); | 54 | ei = btrfs_item_ptr(l, i, struct btrfs_extent_item); |
57 | printf("\t\textent data refs %u owner %Lu\n", | 55 | printk("\t\textent data refs %u owner %Lu\n", |
58 | btrfs_extent_refs(ei), btrfs_extent_owner(ei)); | 56 | btrfs_extent_refs(ei), btrfs_extent_owner(ei)); |
59 | break; | 57 | break; |
60 | case BTRFS_INODE_MAP_ITEM_KEY: | 58 | case BTRFS_INODE_MAP_ITEM_KEY: |
61 | mi = btrfs_item_ptr(l, i, struct btrfs_inode_map_item); | 59 | mi = btrfs_item_ptr(l, i, struct btrfs_inode_map_item); |
62 | printf("\t\tinode map key %Lu %u %Lu\n", | 60 | printk("\t\tinode map key %Lu %u %Lu\n", |
63 | btrfs_disk_key_objectid(&mi->key), | 61 | btrfs_disk_key_objectid(&mi->key), |
64 | btrfs_disk_key_flags(&mi->key), | 62 | btrfs_disk_key_flags(&mi->key), |
65 | btrfs_disk_key_offset(&mi->key)); | 63 | btrfs_disk_key_offset(&mi->key)); |
66 | break; | 64 | break; |
67 | case BTRFS_STRING_ITEM_KEY: | 65 | case BTRFS_STRING_ITEM_KEY: |
68 | printf("\t\titem data %.*s\n", btrfs_item_size(item), | 66 | printk("\t\titem data %.*s\n", btrfs_item_size(item), |
69 | btrfs_leaf_data(l) + btrfs_item_offset(item)); | 67 | btrfs_leaf_data(l) + btrfs_item_offset(item)); |
70 | break; | 68 | break; |
71 | }; | 69 | }; |
@@ -86,12 +84,12 @@ void btrfs_print_tree(struct btrfs_root *root, struct btrfs_buffer *t) | |||
86 | btrfs_print_leaf(root, (struct btrfs_leaf *)c); | 84 | btrfs_print_leaf(root, (struct btrfs_leaf *)c); |
87 | return; | 85 | return; |
88 | } | 86 | } |
89 | printf("node %Lu level %d total ptrs %d free spc %u\n", t->blocknr, | 87 | printk("node %Lu level %d total ptrs %d free spc %u\n", t->blocknr, |
90 | btrfs_header_level(&c->header), nr, | 88 | btrfs_header_level(&c->header), nr, |
91 | (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr); | 89 | (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr); |
92 | fflush(stdout); | 90 | fflush(stdout); |
93 | for (i = 0; i < nr; i++) { | 91 | for (i = 0; i < nr; i++) { |
94 | printf("\tkey %d (%Lu %u %Lu) block %Lu\n", | 92 | printk("\tkey %d (%Lu %u %Lu) block %Lu\n", |
95 | i, | 93 | i, |
96 | c->ptrs[i].key.objectid, | 94 | c->ptrs[i].key.objectid, |
97 | c->ptrs[i].key.flags, | 95 | c->ptrs[i].key.flags, |
diff --git a/fs/btrfs/quick-test.c b/fs/btrfs/quick-test.c deleted file mode 100644 index ef12cf888783..000000000000 --- a/fs/btrfs/quick-test.c +++ /dev/null | |||
@@ -1,179 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include "kerncompat.h" | ||
4 | #include "radix-tree.h" | ||
5 | #include "ctree.h" | ||
6 | #include "disk-io.h" | ||
7 | #include "print-tree.h" | ||
8 | #include "transaction.h" | ||
9 | |||
10 | /* for testing only */ | ||
11 | int next_key(int i, int max_key) { | ||
12 | return rand() % max_key; | ||
13 | // return i; | ||
14 | } | ||
15 | |||
16 | int main(int ac, char **av) { | ||
17 | struct btrfs_key ins; | ||
18 | struct btrfs_key last = { (u64)-1, 0, 0}; | ||
19 | char *buf; | ||
20 | int i; | ||
21 | int num; | ||
22 | int ret; | ||
23 | int run_size = 100000; | ||
24 | int max_key = 100000000; | ||
25 | int tree_size = 0; | ||
26 | struct btrfs_path path; | ||
27 | struct btrfs_super_block super; | ||
28 | struct btrfs_root *root; | ||
29 | struct btrfs_trans_handle *trans; | ||
30 | |||
31 | radix_tree_init(); | ||
32 | |||
33 | root = open_ctree("dbfile", &super); | ||
34 | trans = btrfs_start_transaction(root, 1); | ||
35 | srand(55); | ||
36 | ins.flags = 0; | ||
37 | btrfs_set_key_type(&ins, BTRFS_STRING_ITEM_KEY); | ||
38 | for (i = 0; i < run_size; i++) { | ||
39 | buf = malloc(64); | ||
40 | num = next_key(i, max_key); | ||
41 | // num = i; | ||
42 | sprintf(buf, "string-%d", num); | ||
43 | if (i % 10000 == 0) | ||
44 | fprintf(stderr, "insert %d:%d\n", num, i); | ||
45 | ins.objectid = num; | ||
46 | ins.offset = 0; | ||
47 | ret = btrfs_insert_item(trans, root, &ins, buf, strlen(buf)); | ||
48 | if (!ret) | ||
49 | tree_size++; | ||
50 | free(buf); | ||
51 | if (i == run_size - 5) { | ||
52 | btrfs_commit_transaction(trans, root, &super); | ||
53 | } | ||
54 | |||
55 | } | ||
56 | close_ctree(root, &super); | ||
57 | |||
58 | root = open_ctree("dbfile", &super); | ||
59 | printf("starting search\n"); | ||
60 | srand(55); | ||
61 | for (i = 0; i < run_size; i++) { | ||
62 | num = next_key(i, max_key); | ||
63 | ins.objectid = num; | ||
64 | btrfs_init_path(&path); | ||
65 | if (i % 10000 == 0) | ||
66 | fprintf(stderr, "search %d:%d\n", num, i); | ||
67 | ret = btrfs_search_slot(trans, root, &ins, &path, 0, 0); | ||
68 | if (ret) { | ||
69 | btrfs_print_tree(root, root->node); | ||
70 | printf("unable to find %d\n", num); | ||
71 | exit(1); | ||
72 | } | ||
73 | btrfs_release_path(root, &path); | ||
74 | } | ||
75 | close_ctree(root, &super); | ||
76 | root = open_ctree("dbfile", &super); | ||
77 | printf("node %p level %d total ptrs %d free spc %lu\n", root->node, | ||
78 | btrfs_header_level(&root->node->node.header), | ||
79 | btrfs_header_nritems(&root->node->node.header), | ||
80 | BTRFS_NODEPTRS_PER_BLOCK(root) - | ||
81 | btrfs_header_nritems(&root->node->node.header)); | ||
82 | printf("all searches good, deleting some items\n"); | ||
83 | i = 0; | ||
84 | srand(55); | ||
85 | for (i = 0 ; i < run_size/4; i++) { | ||
86 | num = next_key(i, max_key); | ||
87 | ins.objectid = num; | ||
88 | btrfs_init_path(&path); | ||
89 | ret = btrfs_search_slot(trans, root, &ins, &path, -1, 1); | ||
90 | if (!ret) { | ||
91 | if (i % 10000 == 0) | ||
92 | fprintf(stderr, "del %d:%d\n", num, i); | ||
93 | ret = btrfs_del_item(trans, root, &path); | ||
94 | if (ret != 0) | ||
95 | BUG(); | ||
96 | tree_size--; | ||
97 | } | ||
98 | btrfs_release_path(root, &path); | ||
99 | } | ||
100 | close_ctree(root, &super); | ||
101 | root = open_ctree("dbfile", &super); | ||
102 | srand(128); | ||
103 | for (i = 0; i < run_size; i++) { | ||
104 | buf = malloc(64); | ||
105 | num = next_key(i, max_key); | ||
106 | sprintf(buf, "string-%d", num); | ||
107 | ins.objectid = num; | ||
108 | if (i % 10000 == 0) | ||
109 | fprintf(stderr, "insert %d:%d\n", num, i); | ||
110 | ret = btrfs_insert_item(trans, root, &ins, buf, strlen(buf)); | ||
111 | if (!ret) | ||
112 | tree_size++; | ||
113 | free(buf); | ||
114 | } | ||
115 | close_ctree(root, &super); | ||
116 | root = open_ctree("dbfile", &super); | ||
117 | srand(128); | ||
118 | printf("starting search2\n"); | ||
119 | for (i = 0; i < run_size; i++) { | ||
120 | num = next_key(i, max_key); | ||
121 | ins.objectid = num; | ||
122 | btrfs_init_path(&path); | ||
123 | if (i % 10000 == 0) | ||
124 | fprintf(stderr, "search %d:%d\n", num, i); | ||
125 | ret = btrfs_search_slot(trans, root, &ins, &path, 0, 0); | ||
126 | if (ret) { | ||
127 | btrfs_print_tree(root, root->node); | ||
128 | printf("unable to find %d\n", num); | ||
129 | exit(1); | ||
130 | } | ||
131 | btrfs_release_path(root, &path); | ||
132 | } | ||
133 | printf("starting big long delete run\n"); | ||
134 | while(root->node && | ||
135 | btrfs_header_nritems(&root->node->node.header) > 0) { | ||
136 | struct btrfs_leaf *leaf; | ||
137 | int slot; | ||
138 | ins.objectid = (u64)-1; | ||
139 | btrfs_init_path(&path); | ||
140 | ret = btrfs_search_slot(trans, root, &ins, &path, -1, 1); | ||
141 | if (ret == 0) | ||
142 | BUG(); | ||
143 | |||
144 | leaf = &path.nodes[0]->leaf; | ||
145 | slot = path.slots[0]; | ||
146 | if (slot != btrfs_header_nritems(&leaf->header)) | ||
147 | BUG(); | ||
148 | while(path.slots[0] > 0) { | ||
149 | path.slots[0] -= 1; | ||
150 | slot = path.slots[0]; | ||
151 | leaf = &path.nodes[0]->leaf; | ||
152 | |||
153 | btrfs_disk_key_to_cpu(&last, &leaf->items[slot].key); | ||
154 | if (tree_size % 10000 == 0) | ||
155 | printf("big del %d:%d\n", tree_size, i); | ||
156 | ret = btrfs_del_item(trans, root, &path); | ||
157 | if (ret != 0) { | ||
158 | printf("del_item returned %d\n", ret); | ||
159 | BUG(); | ||
160 | } | ||
161 | tree_size--; | ||
162 | } | ||
163 | btrfs_release_path(root, &path); | ||
164 | } | ||
165 | /* | ||
166 | printf("previous tree:\n"); | ||
167 | btrfs_print_tree(root, root->commit_root); | ||
168 | printf("map before commit\n"); | ||
169 | btrfs_print_tree(root->extent_root, root->extent_root->node); | ||
170 | */ | ||
171 | btrfs_commit_transaction(trans, root, &super); | ||
172 | printf("tree size is now %d\n", tree_size); | ||
173 | printf("root %p commit root %p\n", root->node, root->commit_root); | ||
174 | printf("map tree\n"); | ||
175 | btrfs_print_tree(root->fs_info->extent_root, | ||
176 | root->fs_info->extent_root->node); | ||
177 | close_ctree(root, &super); | ||
178 | return 0; | ||
179 | } | ||
diff --git a/fs/btrfs/radix-tree.c b/fs/btrfs/radix-tree.c deleted file mode 100644 index baa25ca1c2ac..000000000000 --- a/fs/btrfs/radix-tree.c +++ /dev/null | |||
@@ -1,836 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Momchil Velikov | ||
3 | * Portions Copyright (C) 2001 Christoph Hellwig | ||
4 | * Copyright (C) 2005 SGI, Christoph Lameter <clameter@sgi.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation; either version 2, or (at | ||
9 | * your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include "kerncompat.h" | ||
22 | #include "radix-tree.h" | ||
23 | #ifdef __KERNEL__ | ||
24 | #define RADIX_TREE_MAP_SHIFT (CONFIG_BASE_SMALL ? 4 : 6) | ||
25 | #else | ||
26 | #define RADIX_TREE_MAP_SHIFT 3 /* For more stressful testing */ | ||
27 | #endif | ||
28 | |||
29 | #define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT) | ||
30 | #define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE-1) | ||
31 | |||
32 | #define RADIX_TREE_TAG_LONGS \ | ||
33 | ((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) / BITS_PER_LONG) | ||
34 | |||
35 | struct radix_tree_node { | ||
36 | unsigned int count; | ||
37 | void *slots[RADIX_TREE_MAP_SIZE]; | ||
38 | unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; | ||
39 | }; | ||
40 | |||
41 | struct radix_tree_path { | ||
42 | struct radix_tree_node *node; | ||
43 | int offset; | ||
44 | }; | ||
45 | |||
46 | #define RADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long)) | ||
47 | #define RADIX_TREE_MAX_PATH (RADIX_TREE_INDEX_BITS/RADIX_TREE_MAP_SHIFT + 2) | ||
48 | |||
49 | static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH] __read_mostly; | ||
50 | |||
51 | /* | ||
52 | * Per-cpu pool of preloaded nodes | ||
53 | */ | ||
54 | struct radix_tree_preload { | ||
55 | int nr; | ||
56 | struct radix_tree_node *nodes[RADIX_TREE_MAX_PATH]; | ||
57 | }; | ||
58 | struct radix_tree_preload radix_tree_preloads = { 0, }; | ||
59 | |||
60 | static inline gfp_t root_gfp_mask(struct radix_tree_root *root) | ||
61 | { | ||
62 | return root->gfp_mask & __GFP_BITS_MASK; | ||
63 | } | ||
64 | |||
65 | static int internal_nodes = 0; | ||
66 | /* | ||
67 | * This assumes that the caller has performed appropriate preallocation, and | ||
68 | * that the caller has pinned this thread of control to the current CPU. | ||
69 | */ | ||
70 | static struct radix_tree_node * | ||
71 | radix_tree_node_alloc(struct radix_tree_root *root) | ||
72 | { | ||
73 | struct radix_tree_node *ret; | ||
74 | ret = malloc(sizeof(struct radix_tree_node)); | ||
75 | if (ret) { | ||
76 | memset(ret, 0, sizeof(struct radix_tree_node)); | ||
77 | internal_nodes++; | ||
78 | } | ||
79 | return ret; | ||
80 | } | ||
81 | |||
82 | static inline void | ||
83 | radix_tree_node_free(struct radix_tree_node *node) | ||
84 | { | ||
85 | internal_nodes--; | ||
86 | free(node); | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Load up this CPU's radix_tree_node buffer with sufficient objects to | ||
91 | * ensure that the addition of a single element in the tree cannot fail. On | ||
92 | * success, return zero, with preemption disabled. On error, return -ENOMEM | ||
93 | * with preemption not disabled. | ||
94 | */ | ||
95 | int radix_tree_preload(gfp_t gfp_mask) | ||
96 | { | ||
97 | struct radix_tree_preload *rtp; | ||
98 | struct radix_tree_node *node; | ||
99 | int ret = -ENOMEM; | ||
100 | |||
101 | preempt_disable(); | ||
102 | rtp = &__get_cpu_var(radix_tree_preloads); | ||
103 | while (rtp->nr < ARRAY_SIZE(rtp->nodes)) { | ||
104 | preempt_enable(); | ||
105 | node = radix_tree_node_alloc(NULL); | ||
106 | if (node == NULL) | ||
107 | goto out; | ||
108 | preempt_disable(); | ||
109 | rtp = &__get_cpu_var(radix_tree_preloads); | ||
110 | if (rtp->nr < ARRAY_SIZE(rtp->nodes)) | ||
111 | rtp->nodes[rtp->nr++] = node; | ||
112 | else | ||
113 | radix_tree_node_free(node); | ||
114 | } | ||
115 | ret = 0; | ||
116 | out: | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static inline void tag_set(struct radix_tree_node *node, unsigned int tag, | ||
121 | int offset) | ||
122 | { | ||
123 | __set_bit(offset, node->tags[tag]); | ||
124 | } | ||
125 | |||
126 | static inline void tag_clear(struct radix_tree_node *node, unsigned int tag, | ||
127 | int offset) | ||
128 | { | ||
129 | __clear_bit(offset, node->tags[tag]); | ||
130 | } | ||
131 | |||
132 | static inline int tag_get(struct radix_tree_node *node, unsigned int tag, | ||
133 | int offset) | ||
134 | { | ||
135 | return test_bit(offset, node->tags[tag]); | ||
136 | } | ||
137 | |||
138 | static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag) | ||
139 | { | ||
140 | root->gfp_mask |= (__force gfp_t)(1 << (tag + __GFP_BITS_SHIFT)); | ||
141 | } | ||
142 | |||
143 | |||
144 | static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag) | ||
145 | { | ||
146 | root->gfp_mask &= (__force gfp_t)~(1 << (tag + __GFP_BITS_SHIFT)); | ||
147 | } | ||
148 | |||
149 | static inline void root_tag_clear_all(struct radix_tree_root *root) | ||
150 | { | ||
151 | root->gfp_mask &= __GFP_BITS_MASK; | ||
152 | } | ||
153 | |||
154 | static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag) | ||
155 | { | ||
156 | return (__force unsigned)root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT)); | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * Returns 1 if any slot in the node has this tag set. | ||
161 | * Otherwise returns 0. | ||
162 | */ | ||
163 | static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag) | ||
164 | { | ||
165 | int idx; | ||
166 | for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { | ||
167 | if (node->tags[tag][idx]) | ||
168 | return 1; | ||
169 | } | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * Return the maximum key which can be store into a | ||
175 | * radix tree with height HEIGHT. | ||
176 | */ | ||
177 | static inline unsigned long radix_tree_maxindex(unsigned int height) | ||
178 | { | ||
179 | return height_to_maxindex[height]; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Extend a radix tree so it can store key @index. | ||
184 | */ | ||
185 | static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) | ||
186 | { | ||
187 | struct radix_tree_node *node; | ||
188 | unsigned int height; | ||
189 | int tag; | ||
190 | |||
191 | /* Figure out what the height should be. */ | ||
192 | height = root->height + 1; | ||
193 | while (index > radix_tree_maxindex(height)) | ||
194 | height++; | ||
195 | |||
196 | if (root->rnode == NULL) { | ||
197 | root->height = height; | ||
198 | goto out; | ||
199 | } | ||
200 | |||
201 | do { | ||
202 | if (!(node = radix_tree_node_alloc(root))) | ||
203 | return -ENOMEM; | ||
204 | |||
205 | /* Increase the height. */ | ||
206 | node->slots[0] = root->rnode; | ||
207 | |||
208 | /* Propagate the aggregated tag info into the new root */ | ||
209 | for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { | ||
210 | if (root_tag_get(root, tag)) | ||
211 | tag_set(node, tag, 0); | ||
212 | } | ||
213 | |||
214 | node->count = 1; | ||
215 | root->rnode = node; | ||
216 | root->height++; | ||
217 | } while (height > root->height); | ||
218 | out: | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * radix_tree_insert - insert into a radix tree | ||
224 | * @root: radix tree root | ||
225 | * @index: index key | ||
226 | * @item: item to insert | ||
227 | * | ||
228 | * Insert an item into the radix tree at position @index. | ||
229 | */ | ||
230 | int radix_tree_insert(struct radix_tree_root *root, | ||
231 | unsigned long index, void *item) | ||
232 | { | ||
233 | struct radix_tree_node *node = NULL, *slot; | ||
234 | unsigned int height, shift; | ||
235 | int offset; | ||
236 | int error; | ||
237 | |||
238 | /* Make sure the tree is high enough. */ | ||
239 | if (index > radix_tree_maxindex(root->height)) { | ||
240 | error = radix_tree_extend(root, index); | ||
241 | if (error) | ||
242 | return error; | ||
243 | } | ||
244 | |||
245 | slot = root->rnode; | ||
246 | height = root->height; | ||
247 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; | ||
248 | |||
249 | offset = 0; /* uninitialised var warning */ | ||
250 | while (height > 0) { | ||
251 | if (slot == NULL) { | ||
252 | /* Have to add a child node. */ | ||
253 | if (!(slot = radix_tree_node_alloc(root))) | ||
254 | return -ENOMEM; | ||
255 | if (node) { | ||
256 | node->slots[offset] = slot; | ||
257 | node->count++; | ||
258 | } else | ||
259 | root->rnode = slot; | ||
260 | } | ||
261 | |||
262 | /* Go a level down */ | ||
263 | offset = (index >> shift) & RADIX_TREE_MAP_MASK; | ||
264 | node = slot; | ||
265 | slot = node->slots[offset]; | ||
266 | shift -= RADIX_TREE_MAP_SHIFT; | ||
267 | height--; | ||
268 | } | ||
269 | |||
270 | if (slot != NULL) | ||
271 | return -EEXIST; | ||
272 | |||
273 | if (node) { | ||
274 | node->count++; | ||
275 | node->slots[offset] = item; | ||
276 | BUG_ON(tag_get(node, 0, offset)); | ||
277 | BUG_ON(tag_get(node, 1, offset)); | ||
278 | } else { | ||
279 | root->rnode = item; | ||
280 | BUG_ON(root_tag_get(root, 0)); | ||
281 | BUG_ON(root_tag_get(root, 1)); | ||
282 | } | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static inline void **__lookup_slot(struct radix_tree_root *root, | ||
288 | unsigned long index) | ||
289 | { | ||
290 | unsigned int height, shift; | ||
291 | struct radix_tree_node **slot; | ||
292 | |||
293 | height = root->height; | ||
294 | |||
295 | if (index > radix_tree_maxindex(height)) | ||
296 | return NULL; | ||
297 | |||
298 | if (height == 0 && root->rnode) | ||
299 | return (void **)&root->rnode; | ||
300 | |||
301 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; | ||
302 | slot = &root->rnode; | ||
303 | |||
304 | while (height > 0) { | ||
305 | if (*slot == NULL) | ||
306 | return NULL; | ||
307 | |||
308 | slot = (struct radix_tree_node **) | ||
309 | ((*slot)->slots + | ||
310 | ((index >> shift) & RADIX_TREE_MAP_MASK)); | ||
311 | shift -= RADIX_TREE_MAP_SHIFT; | ||
312 | height--; | ||
313 | } | ||
314 | |||
315 | return (void **)slot; | ||
316 | } | ||
317 | |||
318 | /** | ||
319 | * radix_tree_lookup_slot - lookup a slot in a radix tree | ||
320 | * @root: radix tree root | ||
321 | * @index: index key | ||
322 | * | ||
323 | * Lookup the slot corresponding to the position @index in the radix tree | ||
324 | * @root. This is useful for update-if-exists operations. | ||
325 | */ | ||
326 | void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) | ||
327 | { | ||
328 | return __lookup_slot(root, index); | ||
329 | } | ||
330 | |||
331 | /** | ||
332 | * radix_tree_lookup - perform lookup operation on a radix tree | ||
333 | * @root: radix tree root | ||
334 | * @index: index key | ||
335 | * | ||
336 | * Lookup the item at the position @index in the radix tree @root. | ||
337 | */ | ||
338 | void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) | ||
339 | { | ||
340 | void **slot; | ||
341 | |||
342 | slot = __lookup_slot(root, index); | ||
343 | return slot != NULL ? *slot : NULL; | ||
344 | } | ||
345 | |||
346 | /** | ||
347 | * radix_tree_tag_set - set a tag on a radix tree node | ||
348 | * @root: radix tree root | ||
349 | * @index: index key | ||
350 | * @tag: tag index | ||
351 | * | ||
352 | * Set the search tag (which must be < RADIX_TREE_MAX_TAGS) | ||
353 | * corresponding to @index in the radix tree. From | ||
354 | * the root all the way down to the leaf node. | ||
355 | * | ||
356 | * Returns the address of the tagged item. Setting a tag on a not-present | ||
357 | * item is a bug. | ||
358 | */ | ||
359 | void *radix_tree_tag_set(struct radix_tree_root *root, | ||
360 | unsigned long index, unsigned int tag) | ||
361 | { | ||
362 | unsigned int height, shift; | ||
363 | struct radix_tree_node *slot; | ||
364 | |||
365 | height = root->height; | ||
366 | BUG_ON(index > radix_tree_maxindex(height)); | ||
367 | |||
368 | slot = root->rnode; | ||
369 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | ||
370 | |||
371 | while (height > 0) { | ||
372 | int offset; | ||
373 | |||
374 | offset = (index >> shift) & RADIX_TREE_MAP_MASK; | ||
375 | if (!tag_get(slot, tag, offset)) | ||
376 | tag_set(slot, tag, offset); | ||
377 | slot = slot->slots[offset]; | ||
378 | BUG_ON(slot == NULL); | ||
379 | shift -= RADIX_TREE_MAP_SHIFT; | ||
380 | height--; | ||
381 | } | ||
382 | |||
383 | /* set the root's tag bit */ | ||
384 | if (slot && !root_tag_get(root, tag)) | ||
385 | root_tag_set(root, tag); | ||
386 | |||
387 | return slot; | ||
388 | } | ||
389 | |||
390 | /** | ||
391 | * radix_tree_tag_clear - clear a tag on a radix tree node | ||
392 | * @root: radix tree root | ||
393 | * @index: index key | ||
394 | * @tag: tag index | ||
395 | * | ||
396 | * Clear the search tag (which must be < RADIX_TREE_MAX_TAGS) | ||
397 | * corresponding to @index in the radix tree. If | ||
398 | * this causes the leaf node to have no tags set then clear the tag in the | ||
399 | * next-to-leaf node, etc. | ||
400 | * | ||
401 | * Returns the address of the tagged item on success, else NULL. ie: | ||
402 | * has the same return value and semantics as radix_tree_lookup(). | ||
403 | */ | ||
404 | void *radix_tree_tag_clear(struct radix_tree_root *root, | ||
405 | unsigned long index, unsigned int tag) | ||
406 | { | ||
407 | struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; | ||
408 | struct radix_tree_node *slot = NULL; | ||
409 | unsigned int height, shift; | ||
410 | |||
411 | height = root->height; | ||
412 | if (index > radix_tree_maxindex(height)) | ||
413 | goto out; | ||
414 | |||
415 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | ||
416 | pathp->node = NULL; | ||
417 | slot = root->rnode; | ||
418 | |||
419 | while (height > 0) { | ||
420 | int offset; | ||
421 | |||
422 | if (slot == NULL) | ||
423 | goto out; | ||
424 | |||
425 | offset = (index >> shift) & RADIX_TREE_MAP_MASK; | ||
426 | pathp[1].offset = offset; | ||
427 | pathp[1].node = slot; | ||
428 | slot = slot->slots[offset]; | ||
429 | pathp++; | ||
430 | shift -= RADIX_TREE_MAP_SHIFT; | ||
431 | height--; | ||
432 | } | ||
433 | |||
434 | if (slot == NULL) | ||
435 | goto out; | ||
436 | |||
437 | while (pathp->node) { | ||
438 | if (!tag_get(pathp->node, tag, pathp->offset)) | ||
439 | goto out; | ||
440 | tag_clear(pathp->node, tag, pathp->offset); | ||
441 | if (any_tag_set(pathp->node, tag)) | ||
442 | goto out; | ||
443 | pathp--; | ||
444 | } | ||
445 | |||
446 | /* clear the root's tag bit */ | ||
447 | if (root_tag_get(root, tag)) | ||
448 | root_tag_clear(root, tag); | ||
449 | |||
450 | out: | ||
451 | return slot; | ||
452 | } | ||
453 | |||
454 | #ifndef __KERNEL__ /* Only the test harness uses this at present */ | ||
455 | /** | ||
456 | * radix_tree_tag_get - get a tag on a radix tree node | ||
457 | * @root: radix tree root | ||
458 | * @index: index key | ||
459 | * @tag: tag index (< RADIX_TREE_MAX_TAGS) | ||
460 | * | ||
461 | * Return values: | ||
462 | * | ||
463 | * 0: tag not present or not set | ||
464 | * 1: tag set | ||
465 | */ | ||
466 | int radix_tree_tag_get(struct radix_tree_root *root, | ||
467 | unsigned long index, unsigned int tag) | ||
468 | { | ||
469 | unsigned int height, shift; | ||
470 | struct radix_tree_node *slot; | ||
471 | int saw_unset_tag = 0; | ||
472 | |||
473 | height = root->height; | ||
474 | if (index > radix_tree_maxindex(height)) | ||
475 | return 0; | ||
476 | |||
477 | /* check the root's tag bit */ | ||
478 | if (!root_tag_get(root, tag)) | ||
479 | return 0; | ||
480 | |||
481 | if (height == 0) | ||
482 | return 1; | ||
483 | |||
484 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | ||
485 | slot = root->rnode; | ||
486 | |||
487 | for ( ; ; ) { | ||
488 | int offset; | ||
489 | |||
490 | if (slot == NULL) | ||
491 | return 0; | ||
492 | |||
493 | offset = (index >> shift) & RADIX_TREE_MAP_MASK; | ||
494 | |||
495 | /* | ||
496 | * This is just a debug check. Later, we can bale as soon as | ||
497 | * we see an unset tag. | ||
498 | */ | ||
499 | if (!tag_get(slot, tag, offset)) | ||
500 | saw_unset_tag = 1; | ||
501 | if (height == 1) { | ||
502 | int ret = tag_get(slot, tag, offset); | ||
503 | |||
504 | BUG_ON(ret && saw_unset_tag); | ||
505 | return !!ret; | ||
506 | } | ||
507 | slot = slot->slots[offset]; | ||
508 | shift -= RADIX_TREE_MAP_SHIFT; | ||
509 | height--; | ||
510 | } | ||
511 | } | ||
512 | #endif | ||
513 | |||
514 | static unsigned int | ||
515 | __lookup(struct radix_tree_root *root, void **results, unsigned long index, | ||
516 | unsigned int max_items, unsigned long *next_index) | ||
517 | { | ||
518 | unsigned int nr_found = 0; | ||
519 | unsigned int shift, height; | ||
520 | struct radix_tree_node *slot; | ||
521 | unsigned long i; | ||
522 | |||
523 | height = root->height; | ||
524 | if (height == 0) { | ||
525 | if (root->rnode && index == 0) | ||
526 | results[nr_found++] = root->rnode; | ||
527 | goto out; | ||
528 | } | ||
529 | |||
530 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; | ||
531 | slot = root->rnode; | ||
532 | |||
533 | for ( ; height > 1; height--) { | ||
534 | |||
535 | for (i = (index >> shift) & RADIX_TREE_MAP_MASK ; | ||
536 | i < RADIX_TREE_MAP_SIZE; i++) { | ||
537 | if (slot->slots[i] != NULL) | ||
538 | break; | ||
539 | index &= ~((1UL << shift) - 1); | ||
540 | index += 1UL << shift; | ||
541 | if (index == 0) | ||
542 | goto out; /* 32-bit wraparound */ | ||
543 | } | ||
544 | if (i == RADIX_TREE_MAP_SIZE) | ||
545 | goto out; | ||
546 | |||
547 | shift -= RADIX_TREE_MAP_SHIFT; | ||
548 | slot = slot->slots[i]; | ||
549 | } | ||
550 | |||
551 | /* Bottom level: grab some items */ | ||
552 | for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) { | ||
553 | index++; | ||
554 | if (slot->slots[i]) { | ||
555 | results[nr_found++] = slot->slots[i]; | ||
556 | if (nr_found == max_items) | ||
557 | goto out; | ||
558 | } | ||
559 | } | ||
560 | out: | ||
561 | *next_index = index; | ||
562 | return nr_found; | ||
563 | } | ||
564 | |||
565 | /** | ||
566 | * radix_tree_gang_lookup - perform multiple lookup on a radix tree | ||
567 | * @root: radix tree root | ||
568 | * @results: where the results of the lookup are placed | ||
569 | * @first_index: start the lookup from this key | ||
570 | * @max_items: place up to this many items at *results | ||
571 | * | ||
572 | * Performs an index-ascending scan of the tree for present items. Places | ||
573 | * them at *@results and returns the number of items which were placed at | ||
574 | * *@results. | ||
575 | * | ||
576 | * The implementation is naive. | ||
577 | */ | ||
578 | unsigned int | ||
579 | radix_tree_gang_lookup(struct radix_tree_root *root, void **results, | ||
580 | unsigned long first_index, unsigned int max_items) | ||
581 | { | ||
582 | const unsigned long max_index = radix_tree_maxindex(root->height); | ||
583 | unsigned long cur_index = first_index; | ||
584 | unsigned int ret = 0; | ||
585 | |||
586 | while (ret < max_items) { | ||
587 | unsigned int nr_found; | ||
588 | unsigned long next_index; /* Index of next search */ | ||
589 | |||
590 | if (cur_index > max_index) | ||
591 | break; | ||
592 | nr_found = __lookup(root, results + ret, cur_index, | ||
593 | max_items - ret, &next_index); | ||
594 | ret += nr_found; | ||
595 | if (next_index == 0) | ||
596 | break; | ||
597 | cur_index = next_index; | ||
598 | } | ||
599 | return ret; | ||
600 | } | ||
601 | |||
602 | /* | ||
603 | * FIXME: the two tag_get()s here should use find_next_bit() instead of | ||
604 | * open-coding the search. | ||
605 | */ | ||
606 | static unsigned int | ||
607 | __lookup_tag(struct radix_tree_root *root, void **results, unsigned long index, | ||
608 | unsigned int max_items, unsigned long *next_index, unsigned int tag) | ||
609 | { | ||
610 | unsigned int nr_found = 0; | ||
611 | unsigned int shift; | ||
612 | unsigned int height = root->height; | ||
613 | struct radix_tree_node *slot; | ||
614 | |||
615 | if (height == 0) { | ||
616 | if (root->rnode && index == 0) | ||
617 | results[nr_found++] = root->rnode; | ||
618 | goto out; | ||
619 | } | ||
620 | |||
621 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | ||
622 | slot = root->rnode; | ||
623 | |||
624 | do { | ||
625 | unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK; | ||
626 | |||
627 | for ( ; i < RADIX_TREE_MAP_SIZE; i++) { | ||
628 | if (tag_get(slot, tag, i)) { | ||
629 | BUG_ON(slot->slots[i] == NULL); | ||
630 | break; | ||
631 | } | ||
632 | index &= ~((1UL << shift) - 1); | ||
633 | index += 1UL << shift; | ||
634 | if (index == 0) | ||
635 | goto out; /* 32-bit wraparound */ | ||
636 | } | ||
637 | if (i == RADIX_TREE_MAP_SIZE) | ||
638 | goto out; | ||
639 | height--; | ||
640 | if (height == 0) { /* Bottom level: grab some items */ | ||
641 | unsigned long j = index & RADIX_TREE_MAP_MASK; | ||
642 | |||
643 | for ( ; j < RADIX_TREE_MAP_SIZE; j++) { | ||
644 | index++; | ||
645 | if (tag_get(slot, tag, j)) { | ||
646 | BUG_ON(slot->slots[j] == NULL); | ||
647 | results[nr_found++] = slot->slots[j]; | ||
648 | if (nr_found == max_items) | ||
649 | goto out; | ||
650 | } | ||
651 | } | ||
652 | } | ||
653 | shift -= RADIX_TREE_MAP_SHIFT; | ||
654 | slot = slot->slots[i]; | ||
655 | } while (height > 0); | ||
656 | out: | ||
657 | *next_index = index; | ||
658 | return nr_found; | ||
659 | } | ||
660 | |||
661 | /** | ||
662 | * radix_tree_gang_lookup_tag - perform multiple lookup on a radix tree | ||
663 | * based on a tag | ||
664 | * @root: radix tree root | ||
665 | * @results: where the results of the lookup are placed | ||
666 | * @first_index: start the lookup from this key | ||
667 | * @max_items: place up to this many items at *results | ||
668 | * @tag: the tag index (< RADIX_TREE_MAX_TAGS) | ||
669 | * | ||
670 | * Performs an index-ascending scan of the tree for present items which | ||
671 | * have the tag indexed by @tag set. Places the items at *@results and | ||
672 | * returns the number of items which were placed at *@results. | ||
673 | */ | ||
674 | unsigned int | ||
675 | radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, | ||
676 | unsigned long first_index, unsigned int max_items, | ||
677 | unsigned int tag) | ||
678 | { | ||
679 | const unsigned long max_index = radix_tree_maxindex(root->height); | ||
680 | unsigned long cur_index = first_index; | ||
681 | unsigned int ret = 0; | ||
682 | |||
683 | /* check the root's tag bit */ | ||
684 | if (!root_tag_get(root, tag)) | ||
685 | return 0; | ||
686 | |||
687 | while (ret < max_items) { | ||
688 | unsigned int nr_found; | ||
689 | unsigned long next_index; /* Index of next search */ | ||
690 | |||
691 | if (cur_index > max_index) | ||
692 | break; | ||
693 | nr_found = __lookup_tag(root, results + ret, cur_index, | ||
694 | max_items - ret, &next_index, tag); | ||
695 | ret += nr_found; | ||
696 | if (next_index == 0) | ||
697 | break; | ||
698 | cur_index = next_index; | ||
699 | } | ||
700 | return ret; | ||
701 | } | ||
702 | |||
703 | /** | ||
704 | * radix_tree_shrink - shrink height of a radix tree to minimal | ||
705 | * @root radix tree root | ||
706 | */ | ||
707 | static inline void radix_tree_shrink(struct radix_tree_root *root) | ||
708 | { | ||
709 | /* try to shrink tree height */ | ||
710 | while (root->height > 0 && | ||
711 | root->rnode->count == 1 && | ||
712 | root->rnode->slots[0]) { | ||
713 | struct radix_tree_node *to_free = root->rnode; | ||
714 | |||
715 | root->rnode = to_free->slots[0]; | ||
716 | root->height--; | ||
717 | /* must only free zeroed nodes into the slab */ | ||
718 | tag_clear(to_free, 0, 0); | ||
719 | tag_clear(to_free, 1, 0); | ||
720 | to_free->slots[0] = NULL; | ||
721 | to_free->count = 0; | ||
722 | radix_tree_node_free(to_free); | ||
723 | } | ||
724 | } | ||
725 | |||
726 | /** | ||
727 | * radix_tree_delete - delete an item from a radix tree | ||
728 | * @root: radix tree root | ||
729 | * @index: index key | ||
730 | * | ||
731 | * Remove the item at @index from the radix tree rooted at @root. | ||
732 | * | ||
733 | * Returns the address of the deleted item, or NULL if it was not present. | ||
734 | */ | ||
735 | void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) | ||
736 | { | ||
737 | struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; | ||
738 | struct radix_tree_node *slot = NULL; | ||
739 | unsigned int height, shift; | ||
740 | int tag; | ||
741 | int offset; | ||
742 | |||
743 | height = root->height; | ||
744 | if (index > radix_tree_maxindex(height)) | ||
745 | goto out; | ||
746 | |||
747 | slot = root->rnode; | ||
748 | if (height == 0 && root->rnode) { | ||
749 | root_tag_clear_all(root); | ||
750 | root->rnode = NULL; | ||
751 | goto out; | ||
752 | } | ||
753 | |||
754 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | ||
755 | pathp->node = NULL; | ||
756 | |||
757 | do { | ||
758 | if (slot == NULL) | ||
759 | goto out; | ||
760 | |||
761 | pathp++; | ||
762 | offset = (index >> shift) & RADIX_TREE_MAP_MASK; | ||
763 | pathp->offset = offset; | ||
764 | pathp->node = slot; | ||
765 | slot = slot->slots[offset]; | ||
766 | shift -= RADIX_TREE_MAP_SHIFT; | ||
767 | height--; | ||
768 | } while (height > 0); | ||
769 | |||
770 | if (slot == NULL) | ||
771 | goto out; | ||
772 | |||
773 | /* | ||
774 | * Clear all tags associated with the just-deleted item | ||
775 | */ | ||
776 | for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { | ||
777 | if (tag_get(pathp->node, tag, pathp->offset)) | ||
778 | radix_tree_tag_clear(root, index, tag); | ||
779 | } | ||
780 | |||
781 | /* Now free the nodes we do not need anymore */ | ||
782 | while (pathp->node) { | ||
783 | pathp->node->slots[pathp->offset] = NULL; | ||
784 | pathp->node->count--; | ||
785 | |||
786 | if (pathp->node->count) { | ||
787 | if (pathp->node == root->rnode) | ||
788 | radix_tree_shrink(root); | ||
789 | goto out; | ||
790 | } | ||
791 | |||
792 | /* Node with zero slots in use so free it */ | ||
793 | radix_tree_node_free(pathp->node); | ||
794 | |||
795 | pathp--; | ||
796 | } | ||
797 | root_tag_clear_all(root); | ||
798 | root->height = 0; | ||
799 | root->rnode = NULL; | ||
800 | |||
801 | out: | ||
802 | return slot; | ||
803 | } | ||
804 | |||
805 | /** | ||
806 | * radix_tree_tagged - test whether any items in the tree are tagged | ||
807 | * @root: radix tree root | ||
808 | * @tag: tag to test | ||
809 | */ | ||
810 | int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag) | ||
811 | { | ||
812 | return root_tag_get(root, tag); | ||
813 | } | ||
814 | |||
815 | static unsigned long __maxindex(unsigned int height) | ||
816 | { | ||
817 | unsigned int tmp = height * RADIX_TREE_MAP_SHIFT; | ||
818 | unsigned long index = (~0UL >> (RADIX_TREE_INDEX_BITS - tmp - 1)) >> 1; | ||
819 | |||
820 | if (tmp >= RADIX_TREE_INDEX_BITS) | ||
821 | index = ~0UL; | ||
822 | return index; | ||
823 | } | ||
824 | |||
825 | static void radix_tree_init_maxindex(void) | ||
826 | { | ||
827 | unsigned int i; | ||
828 | |||
829 | for (i = 0; i < ARRAY_SIZE(height_to_maxindex); i++) | ||
830 | height_to_maxindex[i] = __maxindex(i); | ||
831 | } | ||
832 | |||
833 | void radix_tree_init(void) | ||
834 | { | ||
835 | radix_tree_init_maxindex(); | ||
836 | } | ||
diff --git a/fs/btrfs/radix-tree.h b/fs/btrfs/radix-tree.h deleted file mode 100644 index c3ce88137f77..000000000000 --- a/fs/btrfs/radix-tree.h +++ /dev/null | |||
@@ -1,73 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Momchil Velikov | ||
3 | * Portions Copyright (C) 2001 Christoph Hellwig | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License as | ||
7 | * published by the Free Software Foundation; either version 2, or (at | ||
8 | * your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | #ifndef _LINUX_RADIX_TREE_H | ||
20 | #define _LINUX_RADIX_TREE_H | ||
21 | |||
22 | #define RADIX_TREE_MAX_TAGS 2 | ||
23 | |||
24 | /* root tags are stored in gfp_mask, shifted by __GFP_BITS_SHIFT */ | ||
25 | struct radix_tree_root { | ||
26 | unsigned int height; | ||
27 | gfp_t gfp_mask; | ||
28 | struct radix_tree_node *rnode; | ||
29 | }; | ||
30 | |||
31 | #define RADIX_TREE_INIT(mask) { \ | ||
32 | .height = 0, \ | ||
33 | .gfp_mask = (mask), \ | ||
34 | .rnode = NULL, \ | ||
35 | } | ||
36 | |||
37 | #define RADIX_TREE(name, mask) \ | ||
38 | struct radix_tree_root name = RADIX_TREE_INIT(mask) | ||
39 | |||
40 | #define INIT_RADIX_TREE(root, mask) \ | ||
41 | do { \ | ||
42 | (root)->height = 0; \ | ||
43 | (root)->gfp_mask = (mask); \ | ||
44 | (root)->rnode = NULL; \ | ||
45 | } while (0) | ||
46 | |||
47 | int radix_tree_insert(struct radix_tree_root *, unsigned long, void *); | ||
48 | void *radix_tree_lookup(struct radix_tree_root *, unsigned long); | ||
49 | void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long); | ||
50 | void *radix_tree_delete(struct radix_tree_root *, unsigned long); | ||
51 | unsigned int | ||
52 | radix_tree_gang_lookup(struct radix_tree_root *root, void **results, | ||
53 | unsigned long first_index, unsigned int max_items); | ||
54 | int radix_tree_preload(gfp_t gfp_mask); | ||
55 | void radix_tree_init(void); | ||
56 | void *radix_tree_tag_set(struct radix_tree_root *root, | ||
57 | unsigned long index, unsigned int tag); | ||
58 | void *radix_tree_tag_clear(struct radix_tree_root *root, | ||
59 | unsigned long index, unsigned int tag); | ||
60 | int radix_tree_tag_get(struct radix_tree_root *root, | ||
61 | unsigned long index, unsigned int tag); | ||
62 | unsigned int | ||
63 | radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, | ||
64 | unsigned long first_index, unsigned int max_items, | ||
65 | unsigned int tag); | ||
66 | int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag); | ||
67 | |||
68 | static inline void radix_tree_preload_end(void) | ||
69 | { | ||
70 | preempt_enable(); | ||
71 | } | ||
72 | |||
73 | #endif /* _LINUX_RADIX_TREE_H */ | ||
diff --git a/fs/btrfs/random-test.c b/fs/btrfs/random-test.c deleted file mode 100644 index 3a38ae7a886d..000000000000 --- a/fs/btrfs/random-test.c +++ /dev/null | |||
@@ -1,405 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <signal.h> | ||
4 | #include "kerncompat.h" | ||
5 | #include "radix-tree.h" | ||
6 | #include "ctree.h" | ||
7 | #include "disk-io.h" | ||
8 | #include "print-tree.h" | ||
9 | #include "transaction.h" | ||
10 | |||
11 | int keep_running = 1; | ||
12 | struct btrfs_super_block super; | ||
13 | |||
14 | static int setup_key(struct radix_tree_root *root, struct btrfs_key *key, | ||
15 | int exists) | ||
16 | { | ||
17 | int num = rand(); | ||
18 | unsigned long res[2]; | ||
19 | int ret; | ||
20 | |||
21 | key->flags = 0; | ||
22 | btrfs_set_key_type(key, BTRFS_STRING_ITEM_KEY); | ||
23 | key->offset = 0; | ||
24 | again: | ||
25 | ret = radix_tree_gang_lookup(root, (void **)res, num, 2); | ||
26 | if (exists) { | ||
27 | if (ret == 0) | ||
28 | return -1; | ||
29 | num = res[0]; | ||
30 | } else if (ret != 0 && num == res[0]) { | ||
31 | num++; | ||
32 | if (ret > 1 && num == res[1]) { | ||
33 | num++; | ||
34 | goto again; | ||
35 | } | ||
36 | } | ||
37 | key->objectid = num; | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static int ins_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
42 | struct radix_tree_root *radix) | ||
43 | { | ||
44 | struct btrfs_path path; | ||
45 | struct btrfs_key key; | ||
46 | int ret; | ||
47 | char buf[128]; | ||
48 | unsigned long oid; | ||
49 | btrfs_init_path(&path); | ||
50 | ret = setup_key(radix, &key, 0); | ||
51 | sprintf(buf, "str-%Lu\n", key.objectid); | ||
52 | ret = btrfs_insert_item(trans, root, &key, buf, strlen(buf)); | ||
53 | if (ret) | ||
54 | goto error; | ||
55 | oid = (unsigned long)key.objectid; | ||
56 | radix_tree_preload(GFP_KERNEL); | ||
57 | ret = radix_tree_insert(radix, oid, (void *)oid); | ||
58 | radix_tree_preload_end(); | ||
59 | if (ret) | ||
60 | goto error; | ||
61 | return ret; | ||
62 | error: | ||
63 | printf("failed to insert %Lu\n", key.objectid); | ||
64 | return -1; | ||
65 | } | ||
66 | |||
67 | static int insert_dup(struct btrfs_trans_handle *trans, struct btrfs_root | ||
68 | *root, struct radix_tree_root *radix) | ||
69 | { | ||
70 | struct btrfs_path path; | ||
71 | struct btrfs_key key; | ||
72 | int ret; | ||
73 | char buf[128]; | ||
74 | btrfs_init_path(&path); | ||
75 | ret = setup_key(radix, &key, 1); | ||
76 | if (ret < 0) | ||
77 | return 0; | ||
78 | sprintf(buf, "str-%Lu\n", key.objectid); | ||
79 | ret = btrfs_insert_item(trans, root, &key, buf, strlen(buf)); | ||
80 | if (ret != -EEXIST) { | ||
81 | printf("insert on %Lu gave us %d\n", key.objectid, ret); | ||
82 | return 1; | ||
83 | } | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
88 | struct radix_tree_root *radix) | ||
89 | { | ||
90 | struct btrfs_path path; | ||
91 | struct btrfs_key key; | ||
92 | int ret; | ||
93 | unsigned long *ptr; | ||
94 | btrfs_init_path(&path); | ||
95 | ret = setup_key(radix, &key, 1); | ||
96 | if (ret < 0) | ||
97 | return 0; | ||
98 | ret = btrfs_search_slot(trans, root, &key, &path, -1, 1); | ||
99 | if (ret) | ||
100 | goto error; | ||
101 | ret = btrfs_del_item(trans, root, &path); | ||
102 | btrfs_release_path(root, &path); | ||
103 | if (ret != 0) | ||
104 | goto error; | ||
105 | ptr = radix_tree_delete(radix, key.objectid); | ||
106 | if (!ptr) | ||
107 | goto error; | ||
108 | return 0; | ||
109 | error: | ||
110 | printf("failed to delete %Lu\n", key.objectid); | ||
111 | return -1; | ||
112 | } | ||
113 | |||
114 | static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root | ||
115 | *root, struct radix_tree_root *radix) | ||
116 | { | ||
117 | struct btrfs_path path; | ||
118 | struct btrfs_key key; | ||
119 | int ret; | ||
120 | btrfs_init_path(&path); | ||
121 | ret = setup_key(radix, &key, 1); | ||
122 | if (ret < 0) | ||
123 | return 0; | ||
124 | ret = btrfs_search_slot(trans, root, &key, &path, 0, 1); | ||
125 | btrfs_release_path(root, &path); | ||
126 | if (ret) | ||
127 | goto error; | ||
128 | return 0; | ||
129 | error: | ||
130 | printf("unable to find key %Lu\n", key.objectid); | ||
131 | return -1; | ||
132 | } | ||
133 | |||
134 | static int lookup_enoent(struct btrfs_trans_handle *trans, struct btrfs_root | ||
135 | *root, struct radix_tree_root *radix) | ||
136 | { | ||
137 | struct btrfs_path path; | ||
138 | struct btrfs_key key; | ||
139 | int ret; | ||
140 | btrfs_init_path(&path); | ||
141 | ret = setup_key(radix, &key, 0); | ||
142 | if (ret < 0) | ||
143 | return ret; | ||
144 | ret = btrfs_search_slot(trans, root, &key, &path, 0, 0); | ||
145 | btrfs_release_path(root, &path); | ||
146 | if (ret <= 0) | ||
147 | goto error; | ||
148 | return 0; | ||
149 | error: | ||
150 | printf("able to find key that should not exist %Lu\n", key.objectid); | ||
151 | return -1; | ||
152 | } | ||
153 | |||
154 | static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root | ||
155 | *root, struct radix_tree_root *radix, int nr) | ||
156 | { | ||
157 | struct btrfs_path path; | ||
158 | struct btrfs_key key; | ||
159 | unsigned long found = 0; | ||
160 | int ret; | ||
161 | int slot; | ||
162 | int *ptr; | ||
163 | int count = 0; | ||
164 | |||
165 | key.offset = 0; | ||
166 | key.flags = 0; | ||
167 | btrfs_set_key_type(&key, BTRFS_STRING_ITEM_KEY); | ||
168 | key.objectid = (unsigned long)-1; | ||
169 | while(nr-- >= 0) { | ||
170 | btrfs_init_path(&path); | ||
171 | ret = btrfs_search_slot(trans, root, &key, &path, -1, 1); | ||
172 | if (ret < 0) { | ||
173 | btrfs_release_path(root, &path); | ||
174 | return ret; | ||
175 | } | ||
176 | if (ret != 0) { | ||
177 | if (path.slots[0] == 0) { | ||
178 | btrfs_release_path(root, &path); | ||
179 | break; | ||
180 | } | ||
181 | path.slots[0] -= 1; | ||
182 | } | ||
183 | slot = path.slots[0]; | ||
184 | found = btrfs_disk_key_objectid( | ||
185 | &path.nodes[0]->leaf.items[slot].key); | ||
186 | ret = btrfs_del_item(trans, root, &path); | ||
187 | count++; | ||
188 | if (ret) { | ||
189 | fprintf(stderr, | ||
190 | "failed to remove %lu from tree\n", | ||
191 | found); | ||
192 | return -1; | ||
193 | } | ||
194 | btrfs_release_path(root, &path); | ||
195 | ptr = radix_tree_delete(radix, found); | ||
196 | if (!ptr) | ||
197 | goto error; | ||
198 | if (!keep_running) | ||
199 | break; | ||
200 | } | ||
201 | return 0; | ||
202 | error: | ||
203 | fprintf(stderr, "failed to delete from the radix %lu\n", found); | ||
204 | return -1; | ||
205 | } | ||
206 | |||
207 | static int fill_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
208 | struct radix_tree_root *radix, int count) | ||
209 | { | ||
210 | int i; | ||
211 | int ret = 0; | ||
212 | for (i = 0; i < count; i++) { | ||
213 | ret = ins_one(trans, root, radix); | ||
214 | if (ret) { | ||
215 | fprintf(stderr, "fill failed\n"); | ||
216 | goto out; | ||
217 | } | ||
218 | if (i % 1000 == 0) { | ||
219 | ret = btrfs_commit_transaction(trans, root, &super); | ||
220 | if (ret) { | ||
221 | fprintf(stderr, "fill commit failed\n"); | ||
222 | return ret; | ||
223 | } | ||
224 | } | ||
225 | if (i && i % 10000 == 0) { | ||
226 | printf("bigfill %d\n", i); | ||
227 | } | ||
228 | if (!keep_running) | ||
229 | break; | ||
230 | } | ||
231 | out: | ||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | static int bulk_op(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
236 | struct radix_tree_root *radix) | ||
237 | { | ||
238 | int ret; | ||
239 | int nr = rand() % 5000; | ||
240 | static int run_nr = 0; | ||
241 | |||
242 | /* do the bulk op much less frequently */ | ||
243 | if (run_nr++ % 100) | ||
244 | return 0; | ||
245 | ret = empty_tree(trans, root, radix, nr); | ||
246 | if (ret) | ||
247 | return ret; | ||
248 | ret = fill_tree(trans, root, radix, nr); | ||
249 | if (ret) | ||
250 | return ret; | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | |||
255 | int (*ops[])(struct btrfs_trans_handle *, | ||
256 | struct btrfs_root *root, struct radix_tree_root *radix) = | ||
257 | { ins_one, insert_dup, del_one, lookup_item, | ||
258 | lookup_enoent, bulk_op }; | ||
259 | |||
260 | static int fill_radix(struct btrfs_root *root, struct radix_tree_root *radix) | ||
261 | { | ||
262 | struct btrfs_path path; | ||
263 | struct btrfs_key key; | ||
264 | unsigned long found; | ||
265 | int ret; | ||
266 | int slot; | ||
267 | int i; | ||
268 | |||
269 | key.offset = 0; | ||
270 | key.flags = 0; | ||
271 | btrfs_set_key_type(&key, BTRFS_STRING_ITEM_KEY); | ||
272 | key.objectid = (unsigned long)-1; | ||
273 | while(1) { | ||
274 | btrfs_init_path(&path); | ||
275 | ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); | ||
276 | if (ret < 0) { | ||
277 | btrfs_release_path(root, &path); | ||
278 | return ret; | ||
279 | } | ||
280 | slot = path.slots[0]; | ||
281 | if (ret != 0) { | ||
282 | if (slot == 0) { | ||
283 | btrfs_release_path(root, &path); | ||
284 | break; | ||
285 | } | ||
286 | slot -= 1; | ||
287 | } | ||
288 | for (i = slot; i >= 0; i--) { | ||
289 | found = btrfs_disk_key_objectid(&path.nodes[0]-> | ||
290 | leaf.items[i].key); | ||
291 | radix_tree_preload(GFP_KERNEL); | ||
292 | ret = radix_tree_insert(radix, found, (void *)found); | ||
293 | if (ret) { | ||
294 | fprintf(stderr, | ||
295 | "failed to insert %lu into radix\n", | ||
296 | found); | ||
297 | exit(1); | ||
298 | } | ||
299 | |||
300 | radix_tree_preload_end(); | ||
301 | } | ||
302 | btrfs_release_path(root, &path); | ||
303 | key.objectid = found - 1; | ||
304 | if (key.objectid > found) | ||
305 | break; | ||
306 | } | ||
307 | return 0; | ||
308 | } | ||
309 | void sigstopper(int ignored) | ||
310 | { | ||
311 | keep_running = 0; | ||
312 | fprintf(stderr, "caught exit signal, stopping\n"); | ||
313 | } | ||
314 | |||
315 | int print_usage(void) | ||
316 | { | ||
317 | printf("usage: tester [-ih] [-c count] [-f count]\n"); | ||
318 | printf("\t -c count -- iteration count after filling\n"); | ||
319 | printf("\t -f count -- run this many random inserts before starting\n"); | ||
320 | printf("\t -i -- only do initial fill\n"); | ||
321 | printf("\t -h -- this help text\n"); | ||
322 | exit(1); | ||
323 | } | ||
324 | int main(int ac, char **av) | ||
325 | { | ||
326 | RADIX_TREE(radix, GFP_KERNEL); | ||
327 | struct btrfs_root *root; | ||
328 | int i; | ||
329 | int ret; | ||
330 | int count; | ||
331 | int op; | ||
332 | int iterations = 20000; | ||
333 | int init_fill_count = 800000; | ||
334 | int err = 0; | ||
335 | int initial_only = 0; | ||
336 | struct btrfs_trans_handle *trans; | ||
337 | radix_tree_init(); | ||
338 | root = open_ctree("dbfile", &super); | ||
339 | fill_radix(root, &radix); | ||
340 | |||
341 | signal(SIGTERM, sigstopper); | ||
342 | signal(SIGINT, sigstopper); | ||
343 | |||
344 | for (i = 1 ; i < ac ; i++) { | ||
345 | if (strcmp(av[i], "-i") == 0) { | ||
346 | initial_only = 1; | ||
347 | } else if (strcmp(av[i], "-c") == 0) { | ||
348 | iterations = atoi(av[i+1]); | ||
349 | i++; | ||
350 | } else if (strcmp(av[i], "-f") == 0) { | ||
351 | init_fill_count = atoi(av[i+1]); | ||
352 | i++; | ||
353 | } else { | ||
354 | print_usage(); | ||
355 | } | ||
356 | } | ||
357 | printf("initial fill\n"); | ||
358 | trans = btrfs_start_transaction(root, 1); | ||
359 | ret = fill_tree(trans, root, &radix, init_fill_count); | ||
360 | printf("starting run\n"); | ||
361 | if (ret) { | ||
362 | err = ret; | ||
363 | goto out; | ||
364 | } | ||
365 | if (initial_only == 1) { | ||
366 | goto out; | ||
367 | } | ||
368 | for (i = 0; i < iterations; i++) { | ||
369 | op = rand() % ARRAY_SIZE(ops); | ||
370 | count = rand() % 128; | ||
371 | if (i % 2000 == 0) { | ||
372 | printf("%d\n", i); | ||
373 | fflush(stdout); | ||
374 | } | ||
375 | if (i && i % 5000 == 0) { | ||
376 | printf("open & close, root level %d nritems %d\n", | ||
377 | btrfs_header_level(&root->node->node.header), | ||
378 | btrfs_header_nritems(&root->node->node.header)); | ||
379 | close_ctree(root, &super); | ||
380 | root = open_ctree("dbfile", &super); | ||
381 | } | ||
382 | while(count--) { | ||
383 | ret = ops[op](trans, root, &radix); | ||
384 | if (ret) { | ||
385 | fprintf(stderr, "op %d failed %d:%d\n", | ||
386 | op, i, iterations); | ||
387 | btrfs_print_tree(root, root->node); | ||
388 | fprintf(stderr, "op %d failed %d:%d\n", | ||
389 | op, i, iterations); | ||
390 | err = ret; | ||
391 | goto out; | ||
392 | } | ||
393 | if (ops[op] == bulk_op) | ||
394 | break; | ||
395 | if (keep_running == 0) { | ||
396 | err = 0; | ||
397 | goto out; | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | out: | ||
402 | close_ctree(root, &super); | ||
403 | return err; | ||
404 | } | ||
405 | |||
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 9cccecc0f431..52c83be4b307 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
@@ -1,7 +1,4 @@ | |||
1 | #include <stdio.h> | 1 | #include <linux/module.h> |
2 | #include <stdlib.h> | ||
3 | #include "kerncompat.h" | ||
4 | #include "radix-tree.h" | ||
5 | #include "ctree.h" | 2 | #include "ctree.h" |
6 | #include "disk-io.h" | 3 | #include "disk-io.h" |
7 | #include "print-tree.h" | 4 | #include "print-tree.h" |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c new file mode 100644 index 000000000000..4ae76044aeab --- /dev/null +++ b/fs/btrfs/super.c | |||
@@ -0,0 +1,205 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/fs.h> | ||
3 | #include <linux/pagemap.h> | ||
4 | #include <linux/highmem.h> | ||
5 | #include <linux/time.h> | ||
6 | #include <linux/init.h> | ||
7 | #include <linux/string.h> | ||
8 | #include <linux/smp_lock.h> | ||
9 | #include <linux/backing-dev.h> | ||
10 | #include "ctree.h" | ||
11 | |||
12 | #define BTRFS_SUPER_MAGIC 0x9123682E | ||
13 | #if 0 | ||
14 | /* some random number */ | ||
15 | |||
16 | static struct super_operations ramfs_ops; | ||
17 | static struct inode_operations ramfs_dir_inode_operations; | ||
18 | |||
19 | static struct backing_dev_info ramfs_backing_dev_info = { | ||
20 | .ra_pages = 0, /* No readahead */ | ||
21 | .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK | | ||
22 | BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY | | ||
23 | BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP, | ||
24 | }; | ||
25 | |||
26 | struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev) | ||
27 | { | ||
28 | struct inode * inode = new_inode(sb); | ||
29 | |||
30 | if (inode) { | ||
31 | inode->i_mode = mode; | ||
32 | inode->i_uid = current->fsuid; | ||
33 | inode->i_gid = current->fsgid; | ||
34 | inode->i_blocks = 0; | ||
35 | inode->i_mapping->a_ops = &ramfs_aops; | ||
36 | inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info; | ||
37 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
38 | switch (mode & S_IFMT) { | ||
39 | default: | ||
40 | init_special_inode(inode, mode, dev); | ||
41 | break; | ||
42 | case S_IFREG: | ||
43 | inode->i_op = &ramfs_file_inode_operations; | ||
44 | inode->i_fop = &ramfs_file_operations; | ||
45 | break; | ||
46 | case S_IFDIR: | ||
47 | inode->i_op = &ramfs_dir_inode_operations; | ||
48 | inode->i_fop = &simple_dir_operations; | ||
49 | |||
50 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
51 | inc_nlink(inode); | ||
52 | break; | ||
53 | case S_IFLNK: | ||
54 | inode->i_op = &page_symlink_inode_operations; | ||
55 | break; | ||
56 | } | ||
57 | } | ||
58 | return inode; | ||
59 | } | ||
60 | |||
61 | /* | ||
62 | * File creation. Allocate an inode, and we're done.. | ||
63 | */ | ||
64 | /* SMP-safe */ | ||
65 | static int | ||
66 | ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | ||
67 | { | ||
68 | struct inode * inode = ramfs_get_inode(dir->i_sb, mode, dev); | ||
69 | int error = -ENOSPC; | ||
70 | |||
71 | if (inode) { | ||
72 | if (dir->i_mode & S_ISGID) { | ||
73 | inode->i_gid = dir->i_gid; | ||
74 | if (S_ISDIR(mode)) | ||
75 | inode->i_mode |= S_ISGID; | ||
76 | } | ||
77 | d_instantiate(dentry, inode); | ||
78 | dget(dentry); /* Extra count - pin the dentry in core */ | ||
79 | error = 0; | ||
80 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; | ||
81 | } | ||
82 | return error; | ||
83 | } | ||
84 | |||
85 | static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) | ||
86 | { | ||
87 | int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0); | ||
88 | if (!retval) | ||
89 | inc_nlink(dir); | ||
90 | return retval; | ||
91 | } | ||
92 | |||
93 | static int ramfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) | ||
94 | { | ||
95 | return ramfs_mknod(dir, dentry, mode | S_IFREG, 0); | ||
96 | } | ||
97 | |||
98 | static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) | ||
99 | { | ||
100 | struct inode *inode; | ||
101 | int error = -ENOSPC; | ||
102 | |||
103 | inode = ramfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); | ||
104 | if (inode) { | ||
105 | int l = strlen(symname)+1; | ||
106 | error = page_symlink(inode, symname, l); | ||
107 | if (!error) { | ||
108 | if (dir->i_mode & S_ISGID) | ||
109 | inode->i_gid = dir->i_gid; | ||
110 | d_instantiate(dentry, inode); | ||
111 | dget(dentry); | ||
112 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; | ||
113 | } else | ||
114 | iput(inode); | ||
115 | } | ||
116 | return error; | ||
117 | } | ||
118 | |||
119 | static struct inode_operations ramfs_dir_inode_operations = { | ||
120 | .create = ramfs_create, | ||
121 | .lookup = simple_lookup, | ||
122 | .link = simple_link, | ||
123 | .unlink = simple_unlink, | ||
124 | .symlink = ramfs_symlink, | ||
125 | .mkdir = ramfs_mkdir, | ||
126 | .rmdir = simple_rmdir, | ||
127 | .mknod = ramfs_mknod, | ||
128 | .rename = simple_rename, | ||
129 | }; | ||
130 | #endif | ||
131 | |||
132 | struct inode *btrfs_get_inode(struct super_block *sb, int mode, dev_t dev) | ||
133 | { | ||
134 | struct inode * inode = new_inode(sb); | ||
135 | |||
136 | if (inode) { | ||
137 | inode->i_mode = mode; | ||
138 | inode->i_uid = current->fsuid; | ||
139 | inode->i_gid = current->fsgid; | ||
140 | inode->i_blocks = 0; | ||
141 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
142 | } | ||
143 | return inode; | ||
144 | } | ||
145 | |||
146 | static struct super_operations btrfs_ops = { | ||
147 | .statfs = simple_statfs, | ||
148 | .drop_inode = generic_delete_inode, | ||
149 | }; | ||
150 | |||
151 | static int btrfs_fill_super(struct super_block * sb, void * data, int silent) | ||
152 | { | ||
153 | struct inode * inode; | ||
154 | struct dentry * root; | ||
155 | |||
156 | sb->s_maxbytes = MAX_LFS_FILESIZE; | ||
157 | sb->s_blocksize = PAGE_CACHE_SIZE; | ||
158 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | ||
159 | sb->s_magic = BTRFS_SUPER_MAGIC; | ||
160 | sb->s_op = &btrfs_ops; | ||
161 | sb->s_time_gran = 1; | ||
162 | inode = btrfs_get_inode(sb, S_IFDIR | 0755, 0); | ||
163 | if (!inode) | ||
164 | return -ENOMEM; | ||
165 | |||
166 | root = d_alloc_root(inode); | ||
167 | if (!root) { | ||
168 | iput(inode); | ||
169 | return -ENOMEM; | ||
170 | } | ||
171 | sb->s_root = root; | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static int btrfs_get_sb(struct file_system_type *fs_type, | ||
176 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) | ||
177 | { | ||
178 | return get_sb_bdev(fs_type, flags, dev_name, data, | ||
179 | btrfs_fill_super, mnt); | ||
180 | } | ||
181 | |||
182 | static struct file_system_type btrfs_fs_type = { | ||
183 | .owner = THIS_MODULE, | ||
184 | .name = "btrfs", | ||
185 | .get_sb = btrfs_get_sb, | ||
186 | .kill_sb = kill_block_super, | ||
187 | .fs_flags = FS_REQUIRES_DEV, | ||
188 | }; | ||
189 | |||
190 | static int __init init_btrfs_fs(void) | ||
191 | { | ||
192 | printk("btrfs loaded!\n"); | ||
193 | return register_filesystem(&btrfs_fs_type); | ||
194 | } | ||
195 | |||
196 | static void __exit exit_btrfs_fs(void) | ||
197 | { | ||
198 | unregister_filesystem(&btrfs_fs_type); | ||
199 | printk("btrfs unloaded\n"); | ||
200 | } | ||
201 | |||
202 | module_init(init_btrfs_fs) | ||
203 | module_exit(exit_btrfs_fs) | ||
204 | |||
205 | MODULE_LICENSE("GPL"); | ||