diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/Makefile | 3 | ||||
-rw-r--r-- | fs/btrfs/TODO | 1 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 123 | ||||
-rw-r--r-- | fs/btrfs/debug-tree.c | 4 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 135 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 3 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 15 | ||||
-rw-r--r-- | fs/btrfs/mkfs.c | 128 | ||||
-rw-r--r-- | fs/btrfs/print-tree.c | 10 | ||||
-rw-r--r-- | fs/btrfs/root-tree.c | 88 |
10 files changed, 445 insertions, 65 deletions
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index f8532200e9ad..13ed6313ac85 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile | |||
@@ -2,7 +2,8 @@ | |||
2 | CC=gcc | 2 | CC=gcc |
3 | CFLAGS = -g -Wall | 3 | CFLAGS = -g -Wall |
4 | headers = radix-tree.h ctree.h disk-io.h kerncompat.h print-tree.h list.h | 4 | headers = radix-tree.h ctree.h disk-io.h kerncompat.h print-tree.h list.h |
5 | objects = ctree.o disk-io.o radix-tree.o mkfs.o extent-tree.o print-tree.o | 5 | objects = ctree.o disk-io.o radix-tree.o mkfs.o extent-tree.o print-tree.o \ |
6 | root-tree.o | ||
6 | 7 | ||
7 | # if you don't have sparse installed, use ls instead | 8 | # if you don't have sparse installed, use ls instead |
8 | CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \ | 9 | CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \ |
diff --git a/fs/btrfs/TODO b/fs/btrfs/TODO index ad29267b8738..ff90e5eaf431 100644 --- a/fs/btrfs/TODO +++ b/fs/btrfs/TODO | |||
@@ -5,6 +5,7 @@ | |||
5 | * make a real mkfs and superblock | 5 | * make a real mkfs and superblock |
6 | * Do checksumming | 6 | * Do checksumming |
7 | * Define FS objects in terms of different item types | 7 | * Define FS objects in terms of different item types |
8 | * add inode tree | ||
8 | * Add block mapping tree (simple dm layer) | 9 | * Add block mapping tree (simple dm layer) |
9 | * Add simple tree locking (semaphore per tree) | 10 | * Add simple tree locking (semaphore per tree) |
10 | * Make allocator smarter | 11 | * Make allocator smarter |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 5dfcc90812c1..0968899fb7f9 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -4,8 +4,13 @@ | |||
4 | #include "list.h" | 4 | #include "list.h" |
5 | #include "kerncompat.h" | 5 | #include "kerncompat.h" |
6 | 6 | ||
7 | #define BTRFS_MAGIC "_BtRfS_M" | ||
7 | #define BTRFS_BLOCKSIZE 1024 | 8 | #define BTRFS_BLOCKSIZE 1024 |
8 | 9 | ||
10 | #define BTRFS_ROOT_TREE_OBJECTID 1 | ||
11 | #define BTRFS_EXTENT_TREE_OBJECTID 2 | ||
12 | #define BTRFS_FS_TREE_OBJECTID 3 | ||
13 | |||
9 | /* | 14 | /* |
10 | * the key defines the order in the tree, and so it also defines (optimal) | 15 | * the key defines the order in the tree, and so it also defines (optimal) |
11 | * block layout. objectid corresonds to the inode number. The flags | 16 | * block layout. objectid corresonds to the inode number. The flags |
@@ -36,7 +41,7 @@ struct btrfs_key { | |||
36 | * every tree block (leaf or node) starts with this header. | 41 | * every tree block (leaf or node) starts with this header. |
37 | */ | 42 | */ |
38 | struct btrfs_header { | 43 | struct btrfs_header { |
39 | __le64 fsid[2]; /* FS specific uuid */ | 44 | u8 fsid[16]; /* FS specific uuid */ |
40 | __le64 blocknr; /* which block this node is supposed to live in */ | 45 | __le64 blocknr; /* which block this node is supposed to live in */ |
41 | __le64 parentid; /* objectid of the tree root */ | 46 | __le64 parentid; /* objectid of the tree root */ |
42 | __le32 csum; | 47 | __le32 csum; |
@@ -52,6 +57,14 @@ struct btrfs_header { | |||
52 | 57 | ||
53 | struct btrfs_buffer; | 58 | struct btrfs_buffer; |
54 | 59 | ||
60 | struct btrfs_root_item { | ||
61 | __le64 blocknr; | ||
62 | __le32 flags; | ||
63 | __le64 block_limit; | ||
64 | __le64 blocks_used; | ||
65 | __le32 refs; | ||
66 | }; | ||
67 | |||
55 | /* | 68 | /* |
56 | * in ram representation of the tree. extent_root is used for all allocations | 69 | * in ram representation of the tree. extent_root is used for all allocations |
57 | * and for the extent tree extent_root root. current_insert is used | 70 | * and for the extent tree extent_root root. current_insert is used |
@@ -61,6 +74,7 @@ struct btrfs_root { | |||
61 | struct btrfs_buffer *node; | 74 | struct btrfs_buffer *node; |
62 | struct btrfs_buffer *commit_root; | 75 | struct btrfs_buffer *commit_root; |
63 | struct btrfs_root *extent_root; | 76 | struct btrfs_root *extent_root; |
77 | struct btrfs_root *tree_root; | ||
64 | struct btrfs_key current_insert; | 78 | struct btrfs_key current_insert; |
65 | struct btrfs_key last_insert; | 79 | struct btrfs_key last_insert; |
66 | int fp; | 80 | int fp; |
@@ -69,28 +83,25 @@ struct btrfs_root { | |||
69 | struct list_head trans; | 83 | struct list_head trans; |
70 | struct list_head cache; | 84 | struct list_head cache; |
71 | int cache_size; | 85 | int cache_size; |
86 | int ref_cows; | ||
87 | struct btrfs_root_item root_item; | ||
88 | struct btrfs_key root_key; | ||
72 | }; | 89 | }; |
73 | 90 | ||
74 | /* | 91 | /* |
75 | * describes a tree on disk | ||
76 | */ | ||
77 | struct btrfs_root_info { | ||
78 | u64 fsid[2]; /* FS specific uuid */ | ||
79 | u64 blocknr; /* blocknr of this block */ | ||
80 | u64 objectid; /* inode number of this root */ | ||
81 | u64 tree_root; /* the tree root block */ | ||
82 | u32 csum; | ||
83 | u32 ham; | ||
84 | u64 snapuuid[2]; /* root specific uuid */ | ||
85 | } __attribute__ ((__packed__)); | ||
86 | |||
87 | /* | ||
88 | * the super block basically lists the main trees of the FS | 92 | * the super block basically lists the main trees of the FS |
89 | * it currently lacks any block count etc etc | 93 | * it currently lacks any block count etc etc |
90 | */ | 94 | */ |
91 | struct btrfs_super_block { | 95 | struct btrfs_super_block { |
92 | struct btrfs_root_info root_info; | 96 | u8 fsid[16]; /* FS specific uuid */ |
93 | struct btrfs_root_info extent_info; | 97 | __le64 blocknr; /* this block number */ |
98 | __le32 csum; | ||
99 | __le64 magic; | ||
100 | __le16 blocksize; | ||
101 | __le64 generation; | ||
102 | __le64 root; | ||
103 | __le64 total_blocks; | ||
104 | __le64 blocks_used; | ||
94 | } __attribute__ ((__packed__)); | 105 | } __attribute__ ((__packed__)); |
95 | 106 | ||
96 | /* | 107 | /* |
@@ -317,6 +328,79 @@ static inline int btrfs_is_leaf(struct btrfs_node *n) | |||
317 | return (btrfs_header_level(&n->header) == 0); | 328 | return (btrfs_header_level(&n->header) == 0); |
318 | } | 329 | } |
319 | 330 | ||
331 | static inline u64 btrfs_root_blocknr(struct btrfs_root_item *item) | ||
332 | { | ||
333 | return le64_to_cpu(item->blocknr); | ||
334 | } | ||
335 | |||
336 | static inline void btrfs_set_root_blocknr(struct btrfs_root_item *item, u64 val) | ||
337 | { | ||
338 | item->blocknr = cpu_to_le64(val); | ||
339 | } | ||
340 | |||
341 | static inline u32 btrfs_root_refs(struct btrfs_root_item *item) | ||
342 | { | ||
343 | return le32_to_cpu(item->refs); | ||
344 | } | ||
345 | |||
346 | static inline void btrfs_set_root_refs(struct btrfs_root_item *item, u32 val) | ||
347 | { | ||
348 | item->refs = cpu_to_le32(val); | ||
349 | } | ||
350 | |||
351 | static inline u64 btrfs_super_blocknr(struct btrfs_super_block *s) | ||
352 | { | ||
353 | return le64_to_cpu(s->blocknr); | ||
354 | } | ||
355 | |||
356 | static inline void btrfs_set_super_blocknr(struct btrfs_super_block *s, u64 val) | ||
357 | { | ||
358 | s->blocknr = cpu_to_le64(val); | ||
359 | } | ||
360 | |||
361 | static inline u64 btrfs_super_root(struct btrfs_super_block *s) | ||
362 | { | ||
363 | return le64_to_cpu(s->root); | ||
364 | } | ||
365 | |||
366 | static inline void btrfs_set_super_root(struct btrfs_super_block *s, u64 val) | ||
367 | { | ||
368 | s->root = cpu_to_le64(val); | ||
369 | } | ||
370 | |||
371 | static inline u64 btrfs_super_total_blocks(struct btrfs_super_block *s) | ||
372 | { | ||
373 | return le64_to_cpu(s->total_blocks); | ||
374 | } | ||
375 | |||
376 | static inline void btrfs_set_super_total_blocks(struct btrfs_super_block *s, | ||
377 | u64 val) | ||
378 | { | ||
379 | s->total_blocks = cpu_to_le64(val); | ||
380 | } | ||
381 | |||
382 | static inline u64 btrfs_super_blocks_used(struct btrfs_super_block *s) | ||
383 | { | ||
384 | return le64_to_cpu(s->blocks_used); | ||
385 | } | ||
386 | |||
387 | static inline void btrfs_set_super_blocks_used(struct btrfs_super_block *s, | ||
388 | u64 val) | ||
389 | { | ||
390 | s->blocks_used = cpu_to_le64(val); | ||
391 | } | ||
392 | |||
393 | static inline u16 btrfs_super_blocksize(struct btrfs_super_block *s) | ||
394 | { | ||
395 | return le16_to_cpu(s->blocksize); | ||
396 | } | ||
397 | |||
398 | static inline void btrfs_set_super_blocksize(struct btrfs_super_block *s, | ||
399 | u16 val) | ||
400 | { | ||
401 | s->blocksize = cpu_to_le16(val); | ||
402 | } | ||
403 | |||
320 | struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_root *root); | 404 | struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_root *root); |
321 | int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf); | 405 | int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf); |
322 | int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks); | 406 | int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks); |
@@ -331,4 +415,11 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); | |||
331 | int btrfs_leaf_free_space(struct btrfs_leaf *leaf); | 415 | int btrfs_leaf_free_space(struct btrfs_leaf *leaf); |
332 | int btrfs_drop_snapshot(struct btrfs_root *root, struct btrfs_buffer *snap); | 416 | int btrfs_drop_snapshot(struct btrfs_root *root, struct btrfs_buffer *snap); |
333 | int btrfs_finish_extent_commit(struct btrfs_root *root); | 417 | int btrfs_finish_extent_commit(struct btrfs_root *root); |
418 | int btrfs_del_root(struct btrfs_root *root, struct btrfs_key *key); | ||
419 | int btrfs_insert_root(struct btrfs_root *root, struct btrfs_key *key, | ||
420 | struct btrfs_root_item *item); | ||
421 | int btrfs_update_root(struct btrfs_root *root, struct btrfs_key *key, | ||
422 | struct btrfs_root_item *item); | ||
423 | int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, | ||
424 | struct btrfs_root_item *item, struct btrfs_key *key); | ||
334 | #endif | 425 | #endif |
diff --git a/fs/btrfs/debug-tree.c b/fs/btrfs/debug-tree.c index 6da0a7aa0f47..de45fb4dfddd 100644 --- a/fs/btrfs/debug-tree.c +++ b/fs/btrfs/debug-tree.c | |||
@@ -11,9 +11,11 @@ int main(int ac, char **av) { | |||
11 | struct btrfs_root *root; | 11 | struct btrfs_root *root; |
12 | radix_tree_init(); | 12 | radix_tree_init(); |
13 | root = open_ctree("dbfile", &super); | 13 | root = open_ctree("dbfile", &super); |
14 | printf("root tree\n"); | 14 | printf("fs tree\n"); |
15 | btrfs_print_tree(root, root->node); | 15 | btrfs_print_tree(root, root->node); |
16 | printf("map tree\n"); | 16 | printf("map tree\n"); |
17 | btrfs_print_tree(root->extent_root, root->extent_root->node); | 17 | btrfs_print_tree(root->extent_root, root->extent_root->node); |
18 | printf("root tree\n"); | ||
19 | btrfs_print_tree(root->tree_root, root->tree_root->node); | ||
18 | return 0; | 20 | return 0; |
19 | } | 21 | } |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c34c0c60935f..3d4bf6833f2a 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -154,41 +154,96 @@ static int __commit_transaction(struct btrfs_root *root) | |||
154 | return ret; | 154 | return ret; |
155 | } | 155 | } |
156 | 156 | ||
157 | static int commit_extent_and_tree_roots(struct btrfs_root *tree_root, | ||
158 | struct btrfs_root *extent_root) | ||
159 | { | ||
160 | int ret; | ||
161 | u64 old_extent_block; | ||
162 | |||
163 | while(1) { | ||
164 | old_extent_block = btrfs_root_blocknr(&extent_root->root_item); | ||
165 | if (old_extent_block == extent_root->node->blocknr) | ||
166 | break; | ||
167 | btrfs_set_root_blocknr(&extent_root->root_item, | ||
168 | extent_root->node->blocknr); | ||
169 | ret = btrfs_update_root(tree_root, | ||
170 | &extent_root->root_key, | ||
171 | &extent_root->root_item); | ||
172 | BUG_ON(ret); | ||
173 | } | ||
174 | __commit_transaction(extent_root); | ||
175 | __commit_transaction(tree_root); | ||
176 | return 0; | ||
177 | } | ||
178 | |||
157 | int btrfs_commit_transaction(struct btrfs_root *root, | 179 | int btrfs_commit_transaction(struct btrfs_root *root, |
158 | struct btrfs_super_block *s) | 180 | struct btrfs_super_block *s) |
159 | { | 181 | { |
160 | int ret = 0; | 182 | int ret = 0; |
183 | struct btrfs_buffer *snap = root->commit_root; | ||
184 | struct btrfs_key snap_key; | ||
161 | 185 | ||
162 | ret = __commit_transaction(root); | 186 | ret = __commit_transaction(root); |
163 | if (!ret && root != root->extent_root) | ||
164 | ret = __commit_transaction(root->extent_root); | ||
165 | BUG_ON(ret); | 187 | BUG_ON(ret); |
166 | if (root->commit_root != root->node) { | 188 | |
167 | struct btrfs_buffer *snap = root->commit_root; | 189 | if (root->commit_root == root->node) |
168 | root->commit_root = root->node; | 190 | return 0; |
169 | root->node->count++; | 191 | |
170 | ret = btrfs_drop_snapshot(root, snap); | 192 | memcpy(&snap_key, &root->root_key, sizeof(snap_key)); |
171 | BUG_ON(ret); | 193 | root->root_key.offset++; |
172 | // btrfs_block_release(root, snap); | 194 | |
173 | } | 195 | btrfs_set_root_blocknr(&root->root_item, root->node->blocknr); |
196 | ret = btrfs_insert_root(root->tree_root, &root->root_key, | ||
197 | &root->root_item); | ||
198 | BUG_ON(ret); | ||
199 | |||
200 | ret = commit_extent_and_tree_roots(root->tree_root, root->extent_root); | ||
201 | BUG_ON(ret); | ||
202 | |||
174 | write_ctree_super(root, s); | 203 | write_ctree_super(root, s); |
175 | btrfs_finish_extent_commit(root); | 204 | btrfs_finish_extent_commit(root->extent_root); |
205 | btrfs_finish_extent_commit(root->tree_root); | ||
206 | |||
207 | root->commit_root = root->node; | ||
208 | root->node->count++; | ||
209 | ret = btrfs_drop_snapshot(root, snap); | ||
210 | BUG_ON(ret); | ||
211 | |||
212 | ret = btrfs_del_root(root->tree_root, &snap_key); | ||
213 | BUG_ON(ret); | ||
214 | |||
176 | return ret; | 215 | return ret; |
177 | } | 216 | } |
178 | 217 | ||
179 | static int __setup_root(struct btrfs_root *root, struct btrfs_root *extent_root, | 218 | static int __setup_root(struct btrfs_root *root, u64 objectid, int fp) |
180 | struct btrfs_root_info *info, int fp) | ||
181 | { | 219 | { |
182 | INIT_LIST_HEAD(&root->trans); | 220 | INIT_LIST_HEAD(&root->trans); |
183 | INIT_LIST_HEAD(&root->cache); | 221 | INIT_LIST_HEAD(&root->cache); |
184 | root->cache_size = 0; | 222 | root->cache_size = 0; |
185 | root->fp = fp; | 223 | root->fp = fp; |
186 | root->node = NULL; | 224 | root->node = NULL; |
187 | root->extent_root = extent_root; | ||
188 | root->commit_root = NULL; | 225 | root->commit_root = NULL; |
189 | root->node = read_tree_block(root, info->tree_root); | ||
190 | memset(&root->current_insert, 0, sizeof(root->current_insert)); | 226 | memset(&root->current_insert, 0, sizeof(root->current_insert)); |
191 | memset(&root->last_insert, 0, sizeof(root->last_insert)); | 227 | memset(&root->last_insert, 0, sizeof(root->last_insert)); |
228 | memset(&root->root_key, 0, sizeof(root->root_key)); | ||
229 | memset(&root->root_item, 0, sizeof(root->root_item)); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static int find_and_setup_root(struct btrfs_root *tree_root, u64 objectid, | ||
234 | struct btrfs_root *root, int fp) | ||
235 | { | ||
236 | int ret; | ||
237 | |||
238 | __setup_root(root, objectid, fp); | ||
239 | ret = btrfs_find_last_root(tree_root, objectid, | ||
240 | &root->root_item, &root->root_key); | ||
241 | BUG_ON(ret); | ||
242 | |||
243 | root->node = read_tree_block(root, | ||
244 | btrfs_root_blocknr(&root->root_item)); | ||
245 | root->ref_cows = 0; | ||
246 | BUG_ON(!root->node); | ||
192 | return 0; | 247 | return 0; |
193 | } | 248 | } |
194 | 249 | ||
@@ -196,9 +251,19 @@ struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) | |||
196 | { | 251 | { |
197 | struct btrfs_root *root = malloc(sizeof(struct btrfs_root)); | 252 | struct btrfs_root *root = malloc(sizeof(struct btrfs_root)); |
198 | struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root)); | 253 | struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root)); |
254 | struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root)); | ||
199 | int fp; | 255 | int fp; |
200 | int ret; | 256 | int ret; |
201 | 257 | ||
258 | root->extent_root = extent_root; | ||
259 | root->tree_root = tree_root; | ||
260 | |||
261 | extent_root->extent_root = extent_root; | ||
262 | extent_root->tree_root = tree_root; | ||
263 | |||
264 | tree_root->extent_root = extent_root; | ||
265 | tree_root->tree_root = tree_root; | ||
266 | |||
202 | fp = open(filename, O_CREAT | O_RDWR, 0600); | 267 | fp = open(filename, O_CREAT | O_RDWR, 0600); |
203 | if (fp < 0) { | 268 | if (fp < 0) { |
204 | free(root); | 269 | free(root); |
@@ -208,11 +273,14 @@ struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) | |||
208 | INIT_RADIX_TREE(&root->pinned_radix, GFP_KERNEL); | 273 | INIT_RADIX_TREE(&root->pinned_radix, GFP_KERNEL); |
209 | INIT_RADIX_TREE(&extent_root->pinned_radix, GFP_KERNEL); | 274 | INIT_RADIX_TREE(&extent_root->pinned_radix, GFP_KERNEL); |
210 | INIT_RADIX_TREE(&extent_root->cache_radix, GFP_KERNEL); | 275 | INIT_RADIX_TREE(&extent_root->cache_radix, GFP_KERNEL); |
276 | INIT_RADIX_TREE(&tree_root->pinned_radix, GFP_KERNEL); | ||
277 | INIT_RADIX_TREE(&tree_root->cache_radix, GFP_KERNEL); | ||
278 | |||
211 | ret = pread(fp, super, sizeof(struct btrfs_super_block), | 279 | ret = pread(fp, super, sizeof(struct btrfs_super_block), |
212 | BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE)); | 280 | BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE)); |
213 | if (ret == 0 || super->root_info.tree_root == 0) { | 281 | if (ret == 0 || btrfs_super_root(super) == 0) { |
214 | printf("making new FS!\n"); | 282 | printf("making new FS!\n"); |
215 | ret = mkfs(fp); | 283 | ret = mkfs(fp, 0, BTRFS_BLOCKSIZE); |
216 | if (ret) | 284 | if (ret) |
217 | return NULL; | 285 | return NULL; |
218 | ret = pread(fp, super, sizeof(struct btrfs_super_block), | 286 | ret = pread(fp, super, sizeof(struct btrfs_super_block), |
@@ -221,24 +289,29 @@ struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) | |||
221 | return NULL; | 289 | return NULL; |
222 | } | 290 | } |
223 | BUG_ON(ret < 0); | 291 | BUG_ON(ret < 0); |
224 | __setup_root(root, extent_root, &super->root_info, fp); | 292 | |
225 | __setup_root(extent_root, extent_root, &super->extent_info, fp); | 293 | __setup_root(tree_root, BTRFS_ROOT_TREE_OBJECTID, fp); |
294 | tree_root->node = read_tree_block(tree_root, btrfs_super_root(super)); | ||
295 | BUG_ON(!tree_root->node); | ||
296 | |||
297 | ret = find_and_setup_root(tree_root, BTRFS_EXTENT_TREE_OBJECTID, | ||
298 | extent_root, fp); | ||
299 | BUG_ON(ret); | ||
300 | |||
301 | ret = find_and_setup_root(tree_root, BTRFS_FS_TREE_OBJECTID, | ||
302 | root, fp); | ||
303 | BUG_ON(ret); | ||
304 | |||
226 | root->commit_root = root->node; | 305 | root->commit_root = root->node; |
227 | root->node->count++; | 306 | root->node->count++; |
307 | root->ref_cows = 1; | ||
228 | return root; | 308 | return root; |
229 | } | 309 | } |
230 | 310 | ||
231 | static int __update_root(struct btrfs_root *root, struct btrfs_root_info *info) | ||
232 | { | ||
233 | info->tree_root = root->node->blocknr; | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | int write_ctree_super(struct btrfs_root *root, struct btrfs_super_block *s) | 311 | int write_ctree_super(struct btrfs_root *root, struct btrfs_super_block *s) |
238 | { | 312 | { |
239 | int ret; | 313 | int ret; |
240 | __update_root(root, &s->root_info); | 314 | btrfs_set_super_root(s, root->tree_root->node->blocknr); |
241 | __update_root(root->extent_root, &s->extent_info); | ||
242 | ret = pwrite(root->fp, s, sizeof(*s), | 315 | ret = pwrite(root->fp, s, sizeof(*s), |
243 | BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE)); | 316 | BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE)); |
244 | if (ret != sizeof(*s)) { | 317 | if (ret != sizeof(*s)) { |
@@ -260,19 +333,25 @@ static int drop_cache(struct btrfs_root *root) | |||
260 | } | 333 | } |
261 | int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s) | 334 | int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s) |
262 | { | 335 | { |
336 | int ret; | ||
263 | btrfs_commit_transaction(root, s); | 337 | btrfs_commit_transaction(root, s); |
264 | __commit_transaction(root->extent_root); | 338 | ret = commit_extent_and_tree_roots(root->tree_root, root->extent_root); |
339 | BUG_ON(ret); | ||
265 | write_ctree_super(root, s); | 340 | write_ctree_super(root, s); |
266 | drop_cache(root->extent_root); | 341 | drop_cache(root->extent_root); |
342 | drop_cache(root->tree_root); | ||
267 | drop_cache(root); | 343 | drop_cache(root); |
268 | BUG_ON(!list_empty(&root->trans)); | 344 | BUG_ON(!list_empty(&root->trans)); |
269 | BUG_ON(!list_empty(&root->extent_root->trans)); | 345 | BUG_ON(!list_empty(&root->extent_root->trans)); |
346 | BUG_ON(!list_empty(&root->tree_root->trans)); | ||
270 | 347 | ||
271 | close(root->fp); | 348 | close(root->fp); |
272 | if (root->node) | 349 | if (root->node) |
273 | btrfs_block_release(root, root->node); | 350 | btrfs_block_release(root, root->node); |
274 | if (root->extent_root->node) | 351 | if (root->extent_root->node) |
275 | btrfs_block_release(root->extent_root, root->extent_root->node); | 352 | btrfs_block_release(root->extent_root, root->extent_root->node); |
353 | if (root->tree_root->node) | ||
354 | btrfs_block_release(root->tree_root, root->tree_root->node); | ||
276 | btrfs_block_release(root, root->commit_root); | 355 | btrfs_block_release(root, root->commit_root); |
277 | free(root); | 356 | free(root); |
278 | printf("on close %d blocks are allocated\n", allocated_blocks); | 357 | printf("on close %d blocks are allocated\n", allocated_blocks); |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index b391335864b1..c22a61f9233f 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -24,7 +24,8 @@ struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *s); | |||
24 | int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s); | 24 | int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s); |
25 | void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf); | 25 | void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf); |
26 | int write_ctree_super(struct btrfs_root *root, struct btrfs_super_block *s); | 26 | int write_ctree_super(struct btrfs_root *root, struct btrfs_super_block *s); |
27 | int mkfs(int fd); | 27 | int mkfs(int fd, u64 num_blocks, u16 blocksize); |
28 | |||
28 | 29 | ||
29 | #define BTRFS_SUPER_INFO_OFFSET(bs) (16 * (bs)) | 30 | #define BTRFS_SUPER_INFO_OFFSET(bs) (16 * (bs)) |
30 | 31 | ||
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index a6969538bca2..21f39b404697 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -82,7 +82,7 @@ int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf) | |||
82 | u64 blocknr; | 82 | u64 blocknr; |
83 | int i; | 83 | int i; |
84 | 84 | ||
85 | if (root == root->extent_root) | 85 | if (!root->ref_cows) |
86 | return 0; | 86 | return 0; |
87 | if (btrfs_is_leaf(&buf->node)) | 87 | if (btrfs_is_leaf(&buf->node)) |
88 | return 0; | 88 | return 0; |
@@ -96,23 +96,22 @@ int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf) | |||
96 | 96 | ||
97 | int btrfs_finish_extent_commit(struct btrfs_root *root) | 97 | int btrfs_finish_extent_commit(struct btrfs_root *root) |
98 | { | 98 | { |
99 | struct btrfs_root *extent_root = root->extent_root; | ||
100 | unsigned long gang[8]; | 99 | unsigned long gang[8]; |
101 | int ret; | 100 | int ret; |
102 | int i; | 101 | int i; |
103 | 102 | ||
104 | while(1) { | 103 | while(1) { |
105 | ret = radix_tree_gang_lookup(&extent_root->pinned_radix, | 104 | ret = radix_tree_gang_lookup(&root->pinned_radix, |
106 | (void **)gang, 0, | 105 | (void **)gang, 0, |
107 | ARRAY_SIZE(gang)); | 106 | ARRAY_SIZE(gang)); |
108 | if (!ret) | 107 | if (!ret) |
109 | break; | 108 | break; |
110 | for (i = 0; i < ret; i++) { | 109 | for (i = 0; i < ret; i++) { |
111 | radix_tree_delete(&extent_root->pinned_radix, gang[i]); | 110 | radix_tree_delete(&root->pinned_radix, gang[i]); |
112 | } | 111 | } |
113 | } | 112 | } |
114 | extent_root->last_insert.objectid = 0; | 113 | root->last_insert.objectid = 0; |
115 | extent_root->last_insert.offset = 0; | 114 | root->last_insert.offset = 0; |
116 | return 0; | 115 | return 0; |
117 | } | 116 | } |
118 | 117 | ||
@@ -173,7 +172,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | |||
173 | refs = btrfs_extent_refs(ei) - 1; | 172 | refs = btrfs_extent_refs(ei) - 1; |
174 | btrfs_set_extent_refs(ei, refs); | 173 | btrfs_set_extent_refs(ei, refs); |
175 | if (refs == 0) { | 174 | if (refs == 0) { |
176 | if (root == extent_root) { | 175 | if (!root->ref_cows) { |
177 | int err; | 176 | int err; |
178 | radix_tree_preload(GFP_KERNEL); | 177 | radix_tree_preload(GFP_KERNEL); |
179 | err = radix_tree_insert(&extent_root->pinned_radix, | 178 | err = radix_tree_insert(&extent_root->pinned_radix, |
@@ -513,7 +512,7 @@ static int walk_up_tree(struct btrfs_root *root, struct btrfs_path *path, | |||
513 | */ | 512 | */ |
514 | int btrfs_drop_snapshot(struct btrfs_root *root, struct btrfs_buffer *snap) | 513 | int btrfs_drop_snapshot(struct btrfs_root *root, struct btrfs_buffer *snap) |
515 | { | 514 | { |
516 | int ret = 0;; | 515 | int ret = 0; |
517 | int wret; | 516 | int wret; |
518 | int level; | 517 | int level; |
519 | struct btrfs_path path; | 518 | struct btrfs_path path; |
diff --git a/fs/btrfs/mkfs.c b/fs/btrfs/mkfs.c index fc1923320de3..dd14ed4fea6c 100644 --- a/fs/btrfs/mkfs.c +++ b/fs/btrfs/mkfs.c | |||
@@ -10,6 +10,120 @@ | |||
10 | #include "ctree.h" | 10 | #include "ctree.h" |
11 | #include "disk-io.h" | 11 | #include "disk-io.h" |
12 | 12 | ||
13 | int mkfs(int fd, u64 num_blocks, u16 blocksize) | ||
14 | { | ||
15 | struct btrfs_super_block super; | ||
16 | struct btrfs_leaf empty_leaf; | ||
17 | struct btrfs_root_item root_item; | ||
18 | struct btrfs_item item; | ||
19 | struct btrfs_extent_item extent_item; | ||
20 | char *block; | ||
21 | int ret; | ||
22 | u16 itemoff; | ||
23 | |||
24 | btrfs_set_super_blocknr(&super, 16); | ||
25 | btrfs_set_super_root(&super, 17); | ||
26 | strcpy((char *)(&super.magic), BTRFS_MAGIC); | ||
27 | btrfs_set_super_blocksize(&super, blocksize); | ||
28 | btrfs_set_super_total_blocks(&super, num_blocks); | ||
29 | btrfs_set_super_blocks_used(&super, 0); | ||
30 | |||
31 | block = malloc(blocksize); | ||
32 | memset(block, 0, blocksize); | ||
33 | BUG_ON(sizeof(super) > blocksize); | ||
34 | memcpy(block, &super, sizeof(super)); | ||
35 | ret = pwrite(fd, block, blocksize, BTRFS_SUPER_INFO_OFFSET(blocksize)); | ||
36 | BUG_ON(ret != blocksize); | ||
37 | |||
38 | /* create the tree of root objects */ | ||
39 | memset(&empty_leaf, 0, sizeof(empty_leaf)); | ||
40 | btrfs_set_header_parentid(&empty_leaf.header, BTRFS_ROOT_TREE_OBJECTID); | ||
41 | btrfs_set_header_blocknr(&empty_leaf.header, 17); | ||
42 | btrfs_set_header_nritems(&empty_leaf.header, 2); | ||
43 | |||
44 | /* create the items for the root tree */ | ||
45 | btrfs_set_root_blocknr(&root_item, 18); | ||
46 | btrfs_set_root_refs(&root_item, 1); | ||
47 | itemoff = LEAF_DATA_SIZE - sizeof(root_item); | ||
48 | btrfs_set_item_offset(&item, itemoff); | ||
49 | btrfs_set_item_size(&item, sizeof(root_item)); | ||
50 | btrfs_set_key_objectid(&item.key, BTRFS_EXTENT_TREE_OBJECTID); | ||
51 | btrfs_set_key_offset(&item.key, 0); | ||
52 | btrfs_set_key_flags(&item.key, 0); | ||
53 | memcpy(empty_leaf.items, &item, sizeof(item)); | ||
54 | memcpy(empty_leaf.data + itemoff, &root_item, sizeof(root_item)); | ||
55 | |||
56 | btrfs_set_root_blocknr(&root_item, 19); | ||
57 | itemoff = itemoff - sizeof(root_item); | ||
58 | btrfs_set_item_offset(&item, itemoff); | ||
59 | btrfs_set_key_objectid(&item.key, BTRFS_FS_TREE_OBJECTID); | ||
60 | memcpy(empty_leaf.items + 1, &item, sizeof(item)); | ||
61 | memcpy(empty_leaf.data + itemoff, &root_item, sizeof(root_item)); | ||
62 | ret = pwrite(fd, &empty_leaf, blocksize, 17 * blocksize); | ||
63 | |||
64 | /* create the items for the extent tree */ | ||
65 | btrfs_set_header_parentid(&empty_leaf.header, | ||
66 | BTRFS_EXTENT_TREE_OBJECTID); | ||
67 | btrfs_set_header_blocknr(&empty_leaf.header, 18); | ||
68 | btrfs_set_header_nritems(&empty_leaf.header, 4); | ||
69 | |||
70 | /* item1, reserve blocks 0-16 */ | ||
71 | btrfs_set_key_objectid(&item.key, 0); | ||
72 | btrfs_set_key_offset(&item.key, 17); | ||
73 | btrfs_set_key_flags(&item.key, 0); | ||
74 | itemoff = LEAF_DATA_SIZE - sizeof(struct btrfs_extent_item); | ||
75 | btrfs_set_item_offset(&item, itemoff); | ||
76 | btrfs_set_item_size(&item, sizeof(struct btrfs_extent_item)); | ||
77 | btrfs_set_extent_refs(&extent_item, 1); | ||
78 | btrfs_set_extent_owner(&extent_item, 0); | ||
79 | memcpy(empty_leaf.items, &item, sizeof(item)); | ||
80 | memcpy(empty_leaf.data + btrfs_item_offset(&item), &extent_item, | ||
81 | btrfs_item_size(&item)); | ||
82 | |||
83 | /* item2, give block 17 to the root */ | ||
84 | btrfs_set_key_objectid(&item.key, 17); | ||
85 | btrfs_set_key_offset(&item.key, 1); | ||
86 | itemoff = itemoff - sizeof(struct btrfs_extent_item); | ||
87 | btrfs_set_item_offset(&item, itemoff); | ||
88 | btrfs_set_extent_owner(&extent_item, BTRFS_ROOT_TREE_OBJECTID); | ||
89 | memcpy(empty_leaf.items + 1, &item, sizeof(item)); | ||
90 | memcpy(empty_leaf.data + btrfs_item_offset(&item), &extent_item, | ||
91 | btrfs_item_size(&item)); | ||
92 | |||
93 | /* item3, give block 18 to the extent root */ | ||
94 | btrfs_set_key_objectid(&item.key, 18); | ||
95 | btrfs_set_key_offset(&item.key, 1); | ||
96 | itemoff = itemoff - sizeof(struct btrfs_extent_item); | ||
97 | btrfs_set_item_offset(&item, itemoff); | ||
98 | btrfs_set_extent_owner(&extent_item, BTRFS_EXTENT_TREE_OBJECTID); | ||
99 | memcpy(empty_leaf.items + 2, &item, sizeof(item)); | ||
100 | memcpy(empty_leaf.data + btrfs_item_offset(&item), &extent_item, | ||
101 | btrfs_item_size(&item)); | ||
102 | |||
103 | /* item4, give block 19 to the FS root */ | ||
104 | btrfs_set_key_objectid(&item.key, 19); | ||
105 | btrfs_set_key_offset(&item.key, 1); | ||
106 | itemoff = itemoff - sizeof(struct btrfs_extent_item); | ||
107 | btrfs_set_item_offset(&item, itemoff); | ||
108 | btrfs_set_extent_owner(&extent_item, BTRFS_FS_TREE_OBJECTID); | ||
109 | memcpy(empty_leaf.items + 3, &item, sizeof(item)); | ||
110 | memcpy(empty_leaf.data + btrfs_item_offset(&item), &extent_item, | ||
111 | btrfs_item_size(&item)); | ||
112 | ret = pwrite(fd, &empty_leaf, blocksize, 18 * blocksize); | ||
113 | if (ret != sizeof(empty_leaf)) | ||
114 | return -1; | ||
115 | |||
116 | /* finally create the FS root */ | ||
117 | btrfs_set_header_parentid(&empty_leaf.header, BTRFS_FS_TREE_OBJECTID); | ||
118 | btrfs_set_header_blocknr(&empty_leaf.header, 19); | ||
119 | btrfs_set_header_nritems(&empty_leaf.header, 0); | ||
120 | ret = pwrite(fd, &empty_leaf, blocksize, 19 * blocksize); | ||
121 | if (ret != sizeof(empty_leaf)) | ||
122 | return -1; | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | #if 0 | ||
13 | int mkfs(int fd) | 127 | int mkfs(int fd) |
14 | { | 128 | { |
15 | struct btrfs_root_info info[2]; | 129 | struct btrfs_root_info info[2]; |
@@ -20,13 +134,14 @@ int mkfs(int fd) | |||
20 | 134 | ||
21 | /* setup the super block area */ | 135 | /* setup the super block area */ |
22 | memset(info, 0, sizeof(info)); | 136 | memset(info, 0, sizeof(info)); |
23 | info[0].blocknr = 16; | 137 | btrfs_set_root_blocknr(info, 16); |
24 | info[0].objectid = 1; | 138 | btrfs_set_root_objectid(info, 1); |
25 | info[0].tree_root = 17; | 139 | btrfs_set_root_tree_root(info, 17); |
140 | |||
141 | btrfs_set_root_blocknr(info + 1, 16); | ||
142 | btrfs_set_root_objectid(info + 1, 2); | ||
143 | btrfs_set_root_tree_root(info + 1, 18); | ||
26 | 144 | ||
27 | info[1].blocknr = 16; | ||
28 | info[1].objectid = 2; | ||
29 | info[1].tree_root = 18; | ||
30 | ret = pwrite(fd, info, sizeof(info), | 145 | ret = pwrite(fd, info, sizeof(info), |
31 | BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE)); | 146 | BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE)); |
32 | if (ret != sizeof(info)) | 147 | if (ret != sizeof(info)) |
@@ -81,3 +196,4 @@ int mkfs(int fd) | |||
81 | return -1; | 196 | return -1; |
82 | return 0; | 197 | return 0; |
83 | } | 198 | } |
199 | #endif | ||
diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index c95c85640aa9..64829b6b90f9 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c | |||
@@ -11,6 +11,7 @@ void btrfs_print_leaf(struct btrfs_leaf *l) | |||
11 | u32 nr = btrfs_header_nritems(&l->header); | 11 | u32 nr = btrfs_header_nritems(&l->header); |
12 | struct btrfs_item *item; | 12 | struct btrfs_item *item; |
13 | struct btrfs_extent_item *ei; | 13 | struct btrfs_extent_item *ei; |
14 | struct btrfs_root_item *ri; | ||
14 | printf("leaf %Lu total ptrs %d free space %d\n", | 15 | printf("leaf %Lu total ptrs %d free space %d\n", |
15 | btrfs_header_blocknr(&l->header), nr, btrfs_leaf_free_space(l)); | 16 | btrfs_header_blocknr(&l->header), nr, btrfs_leaf_free_space(l)); |
16 | fflush(stdout); | 17 | fflush(stdout); |
@@ -23,13 +24,15 @@ void btrfs_print_leaf(struct btrfs_leaf *l) | |||
23 | btrfs_key_offset(&item->key), | 24 | btrfs_key_offset(&item->key), |
24 | btrfs_item_offset(item), | 25 | btrfs_item_offset(item), |
25 | btrfs_item_size(item)); | 26 | btrfs_item_size(item)); |
26 | fflush(stdout); | ||
27 | printf("\t\titem data %.*s\n", btrfs_item_size(item), | 27 | printf("\t\titem data %.*s\n", btrfs_item_size(item), |
28 | l->data + btrfs_item_offset(item)); | 28 | l->data + btrfs_item_offset(item)); |
29 | ei = (struct btrfs_extent_item *)(l->data + | 29 | ei = (struct btrfs_extent_item *)(l->data + |
30 | btrfs_item_offset(item)); | 30 | btrfs_item_offset(item)); |
31 | printf("\t\textent data refs %u owner %Lu\n", ei->refs, | 31 | printf("\t\textent data refs %u owner %Lu\n", |
32 | ei->owner); | 32 | btrfs_extent_refs(ei), btrfs_extent_owner(ei)); |
33 | ri = (struct btrfs_root_item *)ei; | ||
34 | printf("\t\troot data blocknr %Lu refs %u\n", | ||
35 | btrfs_root_blocknr(ri), btrfs_root_refs(ri)); | ||
33 | fflush(stdout); | 36 | fflush(stdout); |
34 | } | 37 | } |
35 | } | 38 | } |
@@ -71,6 +74,5 @@ void btrfs_print_tree(struct btrfs_root *root, struct btrfs_buffer *t) | |||
71 | btrfs_print_tree(root, next_buf); | 74 | btrfs_print_tree(root, next_buf); |
72 | btrfs_block_release(root, next_buf); | 75 | btrfs_block_release(root, next_buf); |
73 | } | 76 | } |
74 | |||
75 | } | 77 | } |
76 | 78 | ||
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c new file mode 100644 index 000000000000..0ab90cfea98f --- /dev/null +++ b/fs/btrfs/root-tree.c | |||
@@ -0,0 +1,88 @@ | |||
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 | |||
9 | int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, | ||
10 | struct btrfs_root_item *item, struct btrfs_key *key) | ||
11 | { | ||
12 | struct btrfs_path path; | ||
13 | struct btrfs_key search_key; | ||
14 | struct btrfs_leaf *l; | ||
15 | int ret; | ||
16 | int slot; | ||
17 | |||
18 | search_key.objectid = objectid; | ||
19 | search_key.flags = (u32)-1; | ||
20 | search_key.offset = (u32)-1; | ||
21 | |||
22 | btrfs_init_path(&path); | ||
23 | ret = btrfs_search_slot(root, &search_key, &path, 0, 0); | ||
24 | if (ret < 0) | ||
25 | goto out; | ||
26 | BUG_ON(ret == 0); | ||
27 | l = &path.nodes[0]->leaf; | ||
28 | BUG_ON(path.slots[0] == 0); | ||
29 | slot = path.slots[0] - 1; | ||
30 | if (btrfs_key_objectid(&l->items[slot].key) != objectid) { | ||
31 | ret = 1; | ||
32 | goto out; | ||
33 | } | ||
34 | memcpy(item, l->data + btrfs_item_offset(l->items + slot), | ||
35 | sizeof(*item)); | ||
36 | btrfs_disk_key_to_cpu(key, &l->items[slot].key); | ||
37 | btrfs_release_path(root, &path); | ||
38 | ret = 0; | ||
39 | out: | ||
40 | return ret; | ||
41 | } | ||
42 | |||
43 | int btrfs_update_root(struct btrfs_root *root, struct btrfs_key *key, | ||
44 | struct btrfs_root_item *item) | ||
45 | { | ||
46 | struct btrfs_path path; | ||
47 | struct btrfs_leaf *l; | ||
48 | int ret; | ||
49 | int slot; | ||
50 | |||
51 | btrfs_init_path(&path); | ||
52 | ret = btrfs_search_slot(root, key, &path, 0, 1); | ||
53 | if (ret < 0) | ||
54 | goto out; | ||
55 | BUG_ON(ret != 0); | ||
56 | l = &path.nodes[0]->leaf; | ||
57 | slot = path.slots[0]; | ||
58 | memcpy(l->data + btrfs_item_offset(l->items + slot), item, | ||
59 | sizeof(*item)); | ||
60 | out: | ||
61 | btrfs_release_path(root, &path); | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | int btrfs_insert_root(struct btrfs_root *root, struct btrfs_key *key, | ||
66 | struct btrfs_root_item *item) | ||
67 | { | ||
68 | int ret; | ||
69 | ret = btrfs_insert_item(root, key, item, sizeof(*item)); | ||
70 | BUG_ON(ret); | ||
71 | return ret; | ||
72 | } | ||
73 | |||
74 | int btrfs_del_root(struct btrfs_root *root, struct btrfs_key *key) | ||
75 | { | ||
76 | struct btrfs_path path; | ||
77 | int ret; | ||
78 | |||
79 | btrfs_init_path(&path); | ||
80 | ret = btrfs_search_slot(root, key, &path, -1, 1); | ||
81 | if (ret < 0) | ||
82 | goto out; | ||
83 | BUG_ON(ret != 0); | ||
84 | ret = btrfs_del_item(root, &path); | ||
85 | out: | ||
86 | btrfs_release_path(root, &path); | ||
87 | return ret; | ||
88 | } | ||