aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-02-20 16:40:44 -0500
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-02-20 16:40:44 -0500
commitd97e63b69ef21c02b67e20e41d9968b0e503572e (patch)
tree400db046be21c09f2d96f74ff98677464c45507f /fs
parent74123bd72a4e34c66e5ad95ce233dd352bebc572 (diff)
Btrfs: early extent mapping support
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/Makefile4
-rw-r--r--fs/btrfs/ctree.c152
-rw-r--r--fs/btrfs/ctree.h34
-rw-r--r--fs/btrfs/disk-io.c76
-rw-r--r--fs/btrfs/disk-io.h3
5 files changed, 236 insertions, 33 deletions
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index 63360212a075..df065dd2dce7 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -4,8 +4,8 @@ CFLAGS= -g -Wall
4.c.o: 4.c.o:
5 $(CC) $(CFLAGS) -c $< 5 $(CC) $(CFLAGS) -c $<
6 6
7ctree: ctree.o disk-io.h ctree.h disk-io.o radix-tree.o radix-tree.h 7ctree: ctree.o disk-io.h ctree.h disk-io.o radix-tree.o radix-tree.h mkfs.o
8 gcc $(CFLAGS) -o ctree ctree.o disk-io.o radix-tree.o 8 gcc $(CFLAGS) -o ctree ctree.o disk-io.o radix-tree.o mkfs.o
9 9
10clean: 10clean:
11 rm ctree *.o 11 rm ctree *.o
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 6b64f49a0279..2177744dedd3 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -5,6 +5,8 @@
5#include "ctree.h" 5#include "ctree.h"
6#include "disk-io.h" 6#include "disk-io.h"
7 7
8static int refill_alloc_extent(struct ctree_root *root);
9
8static inline void init_path(struct ctree_path *p) 10static inline void init_path(struct ctree_path *p)
9{ 11{
10 memset(p, 0, sizeof(*p)); 12 memset(p, 0, sizeof(*p));
@@ -29,7 +31,7 @@ static inline unsigned int leaf_data_end(struct leaf *leaf)
29{ 31{
30 unsigned int nr = leaf->header.nritems; 32 unsigned int nr = leaf->header.nritems;
31 if (nr == 0) 33 if (nr == 0)
32 return ARRAY_SIZE(leaf->data); 34 return sizeof(leaf->data);
33 return leaf->items[nr-1].offset; 35 return leaf->items[nr-1].offset;
34} 36}
35 37
@@ -421,7 +423,7 @@ int insert_ptr(struct ctree_root *root,
421 * due to splitting. Once we've done all the splitting required 423 * due to splitting. Once we've done all the splitting required
422 * do the inserts based on the data in the bal array. 424 * do the inserts based on the data in the bal array.
423 */ 425 */
424 memset(bal, 0, ARRAY_SIZE(bal)); 426 memset(bal, 0, sizeof(bal));
425 while(t && t->node.header.nritems == NODEPTRS_PER_BLOCK) { 427 while(t && t->node.header.nritems == NODEPTRS_PER_BLOCK) {
426 c = &t->node; 428 c = &t->node;
427 if (push_node_left(root, path, 429 if (push_node_left(root, path,
@@ -756,6 +758,7 @@ int insert_item(struct ctree_root *root, struct key *key,
756 if (leaf_free_space(leaf) < 0) 758 if (leaf_free_space(leaf) < 0)
757 BUG(); 759 BUG();
758 release_path(root, &path); 760 release_path(root, &path);
761 refill_alloc_extent(root);
759 return 0; 762 return 0;
760} 763}
761 764
@@ -884,6 +887,135 @@ int del_item(struct ctree_root *root, struct ctree_path *path)
884 return 0; 887 return 0;
885} 888}
886 889
890int next_leaf(struct ctree_root *root, struct ctree_path *path)
891{
892 int slot;
893 int level = 1;
894 u64 blocknr;
895 struct tree_buffer *c;
896 struct tree_buffer *next;
897
898 while(level < MAX_LEVEL) {
899 if (!path->nodes[level])
900 return -1;
901 slot = path->slots[level] + 1;
902 c = path->nodes[level];
903 if (slot >= c->node.header.nritems) {
904 level++;
905 continue;
906 }
907 blocknr = c->node.blockptrs[slot];
908 next = read_tree_block(root, blocknr);
909 break;
910 }
911 path->slots[level] = slot;
912 while(1) {
913 level--;
914 c = path->nodes[level];
915 tree_block_release(root, c);
916 path->nodes[level] = next;
917 path->slots[level] = 0;
918 if (!level)
919 break;
920 next = read_tree_block(root, next->node.blockptrs[0]);
921 }
922 return 0;
923}
924
925int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start,
926 u64 search_end, u64 owner, struct key *ins)
927{
928 struct ctree_path path;
929 struct key *key;
930 int ret;
931 u64 hole_size = 0;
932 int slot = 0;
933 u64 last_block;
934 int start_found = 0;
935 struct leaf *l;
936 struct extent_item extent_item;
937
938 init_path(&path);
939 ins->objectid = search_start;
940 ins->offset = 0;
941 ins->flags = 0;
942
943 ret = search_slot(root, ins, &path);
944 while (1) {
945 l = &path.nodes[0]->leaf;
946 slot = path.slots[0];
947 if (!l) {
948 // FIXME allocate root
949 }
950 if (slot >= l->header.nritems) {
951 ret = next_leaf(root, &path);
952 if (ret == 0)
953 continue;
954 if (!start_found) {
955 ins->objectid = search_start;
956 ins->offset = num_blocks;
957 hole_size = search_end - search_start;
958 goto insert;
959 }
960 ins->objectid = last_block;
961 ins->offset = num_blocks;
962 hole_size = search_end - last_block;
963 goto insert;
964 }
965 key = &l->items[slot].key;
966 if (start_found) {
967 hole_size = key->objectid - last_block;
968 if (hole_size > num_blocks) {
969 ins->objectid = last_block;
970 ins->offset = num_blocks;
971 goto insert;
972 }
973 } else
974 start_found = 1;
975 last_block = key->objectid + key->offset;
976 path.slots[0]++;
977 printf("last block is not %lu\n", last_block);
978 }
979 // FIXME -ENOSPC
980insert:
981 extent_item.refs = 1;
982 extent_item.owner = owner;
983 ret = insert_item(root, ins, &extent_item, sizeof(extent_item));
984 return ret;
985}
986
987static int refill_alloc_extent(struct ctree_root *root)
988{
989 struct alloc_extent *ae = root->alloc_extent;
990 struct key key;
991 int ret;
992 int min_blocks = MAX_LEVEL * 2;
993
994 printf("refill alloc root %p, numused %lu total %lu\n", root, ae->num_used, ae->num_blocks);
995 if (ae->num_blocks > ae->num_used && ae->num_blocks - ae->num_used >
996 min_blocks)
997 return 0;
998 ae = root->reserve_extent;
999 if (ae->num_blocks > ae->num_used) {
1000 if (root->alloc_extent->num_blocks == 0) {
1001 /* we should swap reserve/alloc_extent when alloc
1002 * fills up
1003 */
1004 BUG();
1005 }
1006 if (ae->num_blocks - ae->num_used < min_blocks)
1007 BUG();
1008 return 0;
1009 }
1010 // FIXME, this recurses
1011 ret = alloc_extent(root->extent_root,
1012 min_blocks * 2, 0, (unsigned long)-1, 0, &key);
1013 ae->blocknr = key.objectid;
1014 ae->num_blocks = key.offset;
1015 ae->num_used = 0;
1016 return ret;
1017}
1018
887void print_leaf(struct leaf *l) 1019void print_leaf(struct leaf *l)
888{ 1020{
889 int i; 1021 int i;
@@ -948,8 +1080,8 @@ void print_tree(struct ctree_root *root, struct tree_buffer *t)
948 1080
949/* for testing only */ 1081/* for testing only */
950int next_key(int i, int max_key) { 1082int next_key(int i, int max_key) {
951 return rand() % max_key; 1083 // return rand() % max_key;
952 // return i; 1084 return i;
953} 1085}
954 1086
955int main() { 1087int main() {
@@ -960,7 +1092,7 @@ int main() {
960 int i; 1092 int i;
961 int num; 1093 int num;
962 int ret; 1094 int ret;
963 int run_size = 25000; 1095 int run_size = 256;
964 int max_key = 100000000; 1096 int max_key = 100000000;
965 int tree_size = 0; 1097 int tree_size = 0;
966 struct ctree_path path; 1098 struct ctree_path path;
@@ -980,10 +1112,20 @@ int main() {
980 ins.objectid = num; 1112 ins.objectid = num;
981 ins.offset = 0; 1113 ins.offset = 0;
982 ins.flags = 0; 1114 ins.flags = 0;
1115 printf("insert %d\n", i);
983 ret = insert_item(root, &ins, buf, strlen(buf)); 1116 ret = insert_item(root, &ins, buf, strlen(buf));
984 if (!ret) 1117 if (!ret)
985 tree_size++; 1118 tree_size++;
1119 printf("done insert %d\n", i);
986 } 1120 }
1121 printf("root used: %lu\n", root->alloc_extent->num_used);
1122 printf("root tree\n");
1123 print_tree(root, root->node);
1124 printf("map tree\n");
1125 printf("map used: %lu\n", root->extent_root->alloc_extent->num_used);
1126 print_tree(root->extent_root, root->extent_root->node);
1127 exit(1);
1128
987 close_ctree(root); 1129 close_ctree(root);
988 root = open_ctree("dbfile"); 1130 root = open_ctree("dbfile");
989 printf("starting search\n"); 1131 printf("starting search\n");
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 586bf1866042..b737925be314 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1,7 +1,7 @@
1#ifndef __CTREE__ 1#ifndef __CTREE__
2#define __CTREE__ 2#define __CTREE__
3 3
4#define CTREE_BLOCKSIZE 4096 4#define CTREE_BLOCKSIZE 256
5 5
6struct key { 6struct key {
7 u64 objectid; 7 u64 objectid;
@@ -22,18 +22,41 @@ struct header {
22#define NODEPTRS_PER_BLOCK ((CTREE_BLOCKSIZE - sizeof(struct header)) / \ 22#define NODEPTRS_PER_BLOCK ((CTREE_BLOCKSIZE - sizeof(struct header)) / \
23 (sizeof(struct key) + sizeof(u64))) 23 (sizeof(struct key) + sizeof(u64)))
24 24
25#define LEVEL_BITS 3 25#define MAX_LEVEL 8
26#define MAX_LEVEL (1 << LEVEL_BITS)
27#define node_level(f) ((f) & (MAX_LEVEL-1)) 26#define node_level(f) ((f) & (MAX_LEVEL-1))
28#define is_leaf(f) (node_level(f) == 0) 27#define is_leaf(f) (node_level(f) == 0)
29 28
30struct tree_buffer; 29struct tree_buffer;
30
31struct alloc_extent {
32 u64 blocknr;
33 u64 num_blocks;
34 u64 num_used;
35} __attribute__ ((__packed__));
36
31struct ctree_root { 37struct ctree_root {
32 struct tree_buffer *node; 38 struct tree_buffer *node;
39 struct ctree_root *extent_root;
40 struct alloc_extent *alloc_extent;
41 struct alloc_extent *reserve_extent;
33 int fp; 42 int fp;
34 struct radix_tree_root cache_radix; 43 struct radix_tree_root cache_radix;
44 struct alloc_extent ai1;
45 struct alloc_extent ai2;
35}; 46};
36 47
48struct ctree_root_info {
49 u64 fsid[2]; /* FS specific uuid */
50 u64 blocknr; /* blocknr of this block */
51 u64 objectid; /* inode number of this root */
52 u64 tree_root; /* the tree root */
53 u32 csum;
54 u32 ham;
55 struct alloc_extent alloc_extent;
56 struct alloc_extent reserve_extent;
57 u64 snapuuid[2]; /* root specific uuid */
58} __attribute__ ((__packed__));
59
37struct item { 60struct item {
38 struct key key; 61 struct key key;
39 u16 offset; 62 u16 offset;
@@ -55,6 +78,11 @@ struct node {
55 u64 blockptrs[NODEPTRS_PER_BLOCK]; 78 u64 blockptrs[NODEPTRS_PER_BLOCK];
56} __attribute__ ((__packed__)); 79} __attribute__ ((__packed__));
57 80
81struct extent_item {
82 u32 refs;
83 u64 owner;
84} __attribute__ ((__packed__));
85
58struct ctree_path { 86struct ctree_path {
59 struct tree_buffer *nodes[MAX_LEVEL]; 87 struct tree_buffer *nodes[MAX_LEVEL];
60 int slots[MAX_LEVEL]; 88 int slots[MAX_LEVEL];
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 8d51a07051d9..653f18aab330 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -12,25 +12,27 @@
12 12
13static int allocated_blocks = 0; 13static int allocated_blocks = 0;
14 14
15struct ctree_header {
16 u64 root_block;
17} __attribute__ ((__packed__));
18
19static int get_free_block(struct ctree_root *root, u64 *block) 15static int get_free_block(struct ctree_root *root, u64 *block)
20{ 16{
21 struct stat st; 17 struct stat st;
22 int ret; 18 int ret;
23 19
20 if (root->alloc_extent->num_used >= root->alloc_extent->num_blocks)
21 return -1;
22
23 *block = root->alloc_extent->blocknr + root->alloc_extent->num_used;
24 root->alloc_extent->num_used += 1;
25 if (root->alloc_extent->num_used >= root->alloc_extent->num_blocks) {
26 struct alloc_extent *ae = root->alloc_extent;
27 root->alloc_extent = root->reserve_extent;
28 root->reserve_extent = ae;
29 ae->num_blocks = 0;
30 }
24 st.st_size = 0; 31 st.st_size = 0;
25 ret = fstat(root->fp, &st); 32 ret = fstat(root->fp, &st);
26 if (st.st_size > sizeof(struct ctree_header)) { 33 if (st.st_size < (*block + 1) * CTREE_BLOCKSIZE)
27 *block = (st.st_size - 34 ret = ftruncate(root->fp,
28 sizeof(struct ctree_header)) / CTREE_BLOCKSIZE; 35 (*block + 1) * CTREE_BLOCKSIZE);
29 } else {
30 *block = 0;
31 }
32 ret = ftruncate(root->fp, sizeof(struct ctree_header) + (*block + 1) *
33 CTREE_BLOCKSIZE);
34 return ret; 36 return ret;
35} 37}
36 38
@@ -72,7 +74,7 @@ struct tree_buffer *alloc_free_block(struct ctree_root *root)
72 74
73struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr) 75struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr)
74{ 76{
75 loff_t offset = blocknr * CTREE_BLOCKSIZE + sizeof(struct ctree_header); 77 loff_t offset = blocknr * CTREE_BLOCKSIZE;
76 struct tree_buffer *buf; 78 struct tree_buffer *buf;
77 int ret; 79 int ret;
78 80
@@ -101,7 +103,7 @@ struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr)
101int write_tree_block(struct ctree_root *root, struct tree_buffer *buf) 103int write_tree_block(struct ctree_root *root, struct tree_buffer *buf)
102{ 104{
103 u64 blocknr = buf->blocknr; 105 u64 blocknr = buf->blocknr;
104 loff_t offset = blocknr * CTREE_BLOCKSIZE + sizeof(struct ctree_header); 106 loff_t offset = blocknr * CTREE_BLOCKSIZE;
105 int ret; 107 int ret;
106 108
107 if (buf->blocknr != buf->node.header.blocknr) 109 if (buf->blocknr != buf->node.header.blocknr)
@@ -114,11 +116,32 @@ int write_tree_block(struct ctree_root *root, struct tree_buffer *buf)
114 return 0; 116 return 0;
115} 117}
116 118
119struct ctree_super_block {
120 struct ctree_root_info root_info;
121 struct ctree_root_info extent_info;
122} __attribute__ ((__packed__));
123
124static int __setup_root(struct ctree_root *root, struct ctree_root *extent_root,
125 struct ctree_root_info *info, int fp)
126{
127 root->fp = fp;
128 root->node = read_tree_block(root, info->tree_root);
129 root->extent_root = extent_root;
130 memcpy(&root->ai1, &info->alloc_extent, sizeof(info->alloc_extent));
131 memcpy(&root->ai2, &info->reserve_extent, sizeof(info->reserve_extent));
132 root->alloc_extent = &root->ai1;
133 root->reserve_extent = &root->ai2;
134 INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL);
135 printf("setup done reading root %p, used %lu\n", root, root->alloc_extent->num_used);
136 return 0;
137}
138
117struct ctree_root *open_ctree(char *filename) 139struct ctree_root *open_ctree(char *filename)
118{ 140{
119 struct ctree_root *root = malloc(sizeof(struct ctree_root)); 141 struct ctree_root *root = malloc(sizeof(struct ctree_root));
142 struct ctree_root *extent_root = malloc(sizeof(struct ctree_root));
143 struct ctree_super_block super;
120 int fp; 144 int fp;
121 u64 root_block;
122 int ret; 145 int ret;
123 146
124 fp = open(filename, O_CREAT | O_RDWR); 147 fp = open(filename, O_CREAT | O_RDWR);
@@ -126,14 +149,20 @@ struct ctree_root *open_ctree(char *filename)
126 free(root); 149 free(root);
127 return NULL; 150 return NULL;
128 } 151 }
129 root->fp = fp; 152 ret = pread(fp, &super, sizeof(struct ctree_super_block),
130 INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL); 153 CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE));
131 ret = pread(fp, &root_block, sizeof(u64), 0); 154 if (ret == 0) {
132 if (ret == sizeof(u64)) { 155 ret = mkfs(fp);
133 printf("reading root node at block %lu\n", root_block); 156 if (ret)
134 root->node = read_tree_block(root, root_block); 157 return NULL;
135 } else 158 ret = pread(fp, &super, sizeof(struct ctree_super_block),
136 root->node = NULL; 159 CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE));
160 if (ret != sizeof(struct ctree_super_block))
161 return NULL;
162 }
163 BUG_ON(ret < 0);
164 __setup_root(root, extent_root, &super.root_info, fp);
165 __setup_root(extent_root, extent_root, &super.extent_info, fp);
137 return root; 166 return root;
138} 167}
139 168
@@ -160,6 +189,7 @@ int update_root_block(struct ctree_root *root)
160 189
161void tree_block_release(struct ctree_root *root, struct tree_buffer *buf) 190void tree_block_release(struct ctree_root *root, struct tree_buffer *buf)
162{ 191{
192 return;
163 buf->count--; 193 buf->count--;
164 if (buf->count == 0) { 194 if (buf->count == 0) {
165 if (!radix_tree_lookup(&root->cache_radix, buf->blocknr)) 195 if (!radix_tree_lookup(&root->cache_radix, buf->blocknr))
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index ee95fa05c4a3..41acb65eee19 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -17,5 +17,8 @@ int close_ctree(struct ctree_root *root);
17void tree_block_release(struct ctree_root *root, struct tree_buffer *buf); 17void tree_block_release(struct ctree_root *root, struct tree_buffer *buf);
18struct tree_buffer *alloc_free_block(struct ctree_root *root); 18struct tree_buffer *alloc_free_block(struct ctree_root *root);
19int update_root_block(struct ctree_root *root); 19int update_root_block(struct ctree_root *root);
20int mkfs(int fd);
21
22#define CTREE_SUPER_INFO_OFFSET(bs) (16 * (bs))
20 23
21#endif 24#endif