Loading fs/btrfs/ctree.c +46 −23 Original line number Original line Diff line number Diff line Loading @@ -354,6 +354,7 @@ int __insert_ptr(struct ctree_root *root, c->header.nritems = 2; c->header.nritems = 2; c->header.flags = node_level(level); c->header.flags = node_level(level); c->header.blocknr = t->blocknr; c->header.blocknr = t->blocknr; c->header.parentid = root->node->node.header.parentid; lower = &path->nodes[level-1]->node; lower = &path->nodes[level-1]->node; if (is_leaf(lower->header.flags)) if (is_leaf(lower->header.flags)) lower_key = &((struct leaf *)lower)->items[0].key; lower_key = &((struct leaf *)lower)->items[0].key; Loading @@ -363,7 +364,7 @@ int __insert_ptr(struct ctree_root *root, memcpy(c->keys + 1, key, sizeof(struct key)); memcpy(c->keys + 1, key, sizeof(struct key)); c->blockptrs[0] = path->nodes[level-1]->blocknr; c->blockptrs[0] = path->nodes[level-1]->blocknr; c->blockptrs[1] = blocknr; c->blockptrs[1] = blocknr; /* the path has an extra ref to root->node */ /* the super has an extra ref to root->node */ tree_block_release(root, root->node); tree_block_release(root, root->node); root->node = t; root->node = t; t->count++; t->count++; Loading Loading @@ -439,6 +440,7 @@ int insert_ptr(struct ctree_root *root, b = &b_buffer->node; b = &b_buffer->node; b->header.flags = c->header.flags; b->header.flags = c->header.flags; b->header.blocknr = b_buffer->blocknr; b->header.blocknr = b_buffer->blocknr; b->header.parentid = root->node->node.header.parentid; mid = (c->header.nritems + 1) / 2; mid = (c->header.nritems + 1) / 2; memcpy(b->keys, c->keys + mid, memcpy(b->keys, c->keys + mid, (c->header.nritems - mid) * sizeof(struct key)); (c->header.nritems - mid) * sizeof(struct key)); Loading Loading @@ -642,6 +644,7 @@ int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size) right->header.nritems = nritems - mid; right->header.nritems = nritems - mid; right->header.blocknr = right_buffer->blocknr; right->header.blocknr = right_buffer->blocknr; right->header.flags = node_level(0); right->header.flags = node_level(0); right->header.parentid = root->node->node.header.parentid; data_copy_size = l->items[mid].offset + l->items[mid].size - data_copy_size = l->items[mid].offset + l->items[mid].size - leaf_data_end(l); leaf_data_end(l); memcpy(right->items, l->items + mid, memcpy(right->items, l->items + mid, Loading Loading @@ -689,8 +692,12 @@ int insert_item(struct ctree_root *root, struct key *key, unsigned int data_end; unsigned int data_end; struct ctree_path path; struct ctree_path path; refill_alloc_extent(root); /* create a root if there isn't one */ /* create a root if there isn't one */ if (!root->node) { if (!root->node) { BUG(); #if 0 struct tree_buffer *t; struct tree_buffer *t; t = alloc_free_block(root); t = alloc_free_block(root); BUG_ON(!t); BUG_ON(!t); Loading @@ -699,6 +706,7 @@ int insert_item(struct ctree_root *root, struct key *key, t->node.header.blocknr = t->blocknr; t->node.header.blocknr = t->blocknr; root->node = t; root->node = t; write_tree_block(root, t); write_tree_block(root, t); #endif } } init_path(&path); init_path(&path); ret = search_slot(root, key, &path); ret = search_slot(root, key, &path); Loading Loading @@ -758,7 +766,6 @@ int insert_item(struct ctree_root *root, struct key *key, if (leaf_free_space(leaf) < 0) if (leaf_free_space(leaf) < 0) BUG(); BUG(); release_path(root, &path); release_path(root, &path); refill_alloc_extent(root); return 0; return 0; } } Loading Loading @@ -893,7 +900,7 @@ int next_leaf(struct ctree_root *root, struct ctree_path *path) int level = 1; int level = 1; u64 blocknr; u64 blocknr; struct tree_buffer *c; struct tree_buffer *c; struct tree_buffer *next; struct tree_buffer *next = NULL; while(level < MAX_LEVEL) { while(level < MAX_LEVEL) { if (!path->nodes[level]) if (!path->nodes[level]) Loading @@ -905,6 +912,8 @@ int next_leaf(struct ctree_root *root, struct ctree_path *path) continue; continue; } } blocknr = c->node.blockptrs[slot]; blocknr = c->node.blockptrs[slot]; if (next) tree_block_release(root, next); next = read_tree_block(root, blocknr); next = read_tree_block(root, blocknr); break; break; } } Loading @@ -922,7 +931,7 @@ int next_leaf(struct ctree_root *root, struct ctree_path *path) return 0; return 0; } } int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start, int alloc_extent(struct ctree_root *orig_root, u64 num_blocks, u64 search_start, u64 search_end, u64 owner, struct key *ins) u64 search_end, u64 owner, struct key *ins) { { struct ctree_path path; struct ctree_path path; Loading @@ -934,6 +943,7 @@ int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start, int start_found = 0; int start_found = 0; struct leaf *l; struct leaf *l; struct extent_item extent_item; struct extent_item extent_item; struct ctree_root * root = orig_root->extent_root; init_path(&path); init_path(&path); ins->objectid = search_start; ins->objectid = search_start; Loading Loading @@ -974,13 +984,18 @@ int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start, start_found = 1; start_found = 1; last_block = key->objectid + key->offset; last_block = key->objectid + key->offset; path.slots[0]++; path.slots[0]++; printf("last block is not %lu\n", last_block); } } // FIXME -ENOSPC // FIXME -ENOSPC insert: insert: release_path(root, &path); extent_item.refs = 1; extent_item.refs = 1; extent_item.owner = owner; extent_item.owner = owner; ret = insert_item(root, ins, &extent_item, sizeof(extent_item)); if (root == orig_root && root->reserve_extent->num_blocks == 0) { root->reserve_extent->blocknr = ins->objectid; root->reserve_extent->num_blocks = ins->offset; root->reserve_extent->num_used = 0; } ret = insert_item(root->extent_root, ins, &extent_item, sizeof(extent_item)); return ret; return ret; } } Loading @@ -991,7 +1006,6 @@ static int refill_alloc_extent(struct ctree_root *root) int ret; int ret; int min_blocks = MAX_LEVEL * 2; int min_blocks = MAX_LEVEL * 2; printf("refill alloc root %p, numused %lu total %lu\n", root, ae->num_used, ae->num_blocks); if (ae->num_blocks > ae->num_used && ae->num_blocks - ae->num_used > if (ae->num_blocks > ae->num_used && ae->num_blocks - ae->num_used > min_blocks) min_blocks) return 0; return 0; Loading @@ -1007,9 +1021,9 @@ static int refill_alloc_extent(struct ctree_root *root) BUG(); BUG(); return 0; return 0; } } // FIXME, this recurses ret = alloc_extent(root, ret = alloc_extent(root->extent_root, min_blocks * 2, 0, (unsigned long)-1, min_blocks * 2, 0, (unsigned long)-1, 0, &key); root->node->node.header.parentid, &key); ae->blocknr = key.objectid; ae->blocknr = key.objectid; ae->num_blocks = key.offset; ae->num_blocks = key.offset; ae->num_used = 0; ae->num_used = 0; Loading @@ -1021,6 +1035,7 @@ void print_leaf(struct leaf *l) int i; int i; int nr = l->header.nritems; int nr = l->header.nritems; struct item *item; struct item *item; struct extent_item *ei; printf("leaf %lu total ptrs %d free space %d\n", l->header.blocknr, nr, printf("leaf %lu total ptrs %d free space %d\n", l->header.blocknr, nr, leaf_free_space(l)); leaf_free_space(l)); fflush(stdout); fflush(stdout); Loading @@ -1032,6 +1047,8 @@ void print_leaf(struct leaf *l) item->offset, item->size); item->offset, item->size); fflush(stdout); fflush(stdout); printf("\t\titem data %.*s\n", item->size, l->data+item->offset); printf("\t\titem data %.*s\n", item->size, l->data+item->offset); ei = (struct extent_item *)(l->data + item->offset); printf("\t\textent data %u %lu\n", ei->refs, ei->owner); fflush(stdout); fflush(stdout); } } } } Loading Loading @@ -1080,8 +1097,8 @@ void print_tree(struct ctree_root *root, struct tree_buffer *t) /* for testing only */ /* for testing only */ int next_key(int i, int max_key) { int next_key(int i, int max_key) { // return rand() % max_key; return rand() % max_key; return i; // return i; } } int main() { int main() { Loading @@ -1092,15 +1109,20 @@ int main() { int i; int i; int num; int num; int ret; int ret; int run_size = 256; int run_size = 10000; int max_key = 100000000; int max_key = 100000000; int tree_size = 0; int tree_size = 0; struct ctree_path path; struct ctree_path path; struct ctree_super_block super; radix_tree_init(); radix_tree_init(); root = open_ctree("dbfile"); root = open_ctree("dbfile", &super); printf("root tree\n"); print_tree(root, root->node); printf("map tree\n"); print_tree(root->extent_root, root->extent_root->node); srand(55); srand(55); for (i = 0; i < run_size; i++) { for (i = 0; i < run_size; i++) { Loading @@ -1112,22 +1134,20 @@ int main() { ins.objectid = num; ins.objectid = num; ins.offset = 0; ins.offset = 0; ins.flags = 0; ins.flags = 0; printf("insert %d\n", i); ret = insert_item(root, &ins, buf, strlen(buf)); ret = insert_item(root, &ins, buf, strlen(buf)); if (!ret) if (!ret) tree_size++; tree_size++; printf("done insert %d\n", i); } } printf("root used: %lu\n", root->alloc_extent->num_used); printf("root used: %lu\n", root->alloc_extent->num_used); printf("root tree\n"); printf("root tree\n"); print_tree(root, root->node); // print_tree(root, root->node); printf("map tree\n"); printf("map tree\n"); printf("map used: %lu\n", root->extent_root->alloc_extent->num_used); printf("map used: %lu\n", root->extent_root->alloc_extent->num_used); print_tree(root->extent_root, root->extent_root->node); // print_tree(root->extent_root, root->extent_root->node); exit(1); write_ctree_super(root, &super); close_ctree(root); close_ctree(root); root = open_ctree("dbfile"); root = open_ctree("dbfile", &super); printf("starting search\n"); printf("starting search\n"); srand(55); srand(55); for (i = 0; i < run_size; i++) { for (i = 0; i < run_size; i++) { Loading @@ -1142,8 +1162,9 @@ int main() { } } release_path(root, &path); release_path(root, &path); } } write_ctree_super(root, &super); close_ctree(root); close_ctree(root); root = open_ctree("dbfile"); root = open_ctree("dbfile", &super); printf("node %p level %d total ptrs %d free spc %lu\n", root->node, printf("node %p level %d total ptrs %d free spc %lu\n", root->node, node_level(root->node->node.header.flags), node_level(root->node->node.header.flags), root->node->node.header.nritems, root->node->node.header.nritems, Loading Loading @@ -1174,8 +1195,9 @@ int main() { if (!ret) if (!ret) tree_size++; tree_size++; } } write_ctree_super(root, &super); close_ctree(root); close_ctree(root); root = open_ctree("dbfile"); root = open_ctree("dbfile", &super); printf("starting search2\n"); printf("starting search2\n"); srand(128); srand(128); for (i = 0; i < run_size; i++) { for (i = 0; i < run_size; i++) { Loading Loading @@ -1221,6 +1243,7 @@ int main() { } } release_path(root, &path); release_path(root, &path); } } write_ctree_super(root, &super); close_ctree(root); close_ctree(root); printf("tree size is now %d\n", tree_size); printf("tree size is now %d\n", tree_size); return 0; return 0; Loading fs/btrfs/ctree.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,11 @@ struct ctree_root_info { u64 snapuuid[2]; /* root specific uuid */ u64 snapuuid[2]; /* root specific uuid */ } __attribute__ ((__packed__)); } __attribute__ ((__packed__)); struct ctree_super_block { struct ctree_root_info root_info; struct ctree_root_info extent_info; } __attribute__ ((__packed__)); struct item { struct item { struct key key; struct key key; u16 offset; u16 offset; Loading fs/btrfs/disk-io.c +45 −34 Original line number Original line Diff line number Diff line Loading @@ -15,7 +15,7 @@ static int allocated_blocks = 0; static int get_free_block(struct ctree_root *root, u64 *block) static int get_free_block(struct ctree_root *root, u64 *block) { { struct stat st; struct stat st; int ret; int ret = 0; if (root->alloc_extent->num_used >= root->alloc_extent->num_blocks) if (root->alloc_extent->num_used >= root->alloc_extent->num_blocks) return -1; return -1; Loading @@ -30,9 +30,14 @@ static int get_free_block(struct ctree_root *root, u64 *block) } } st.st_size = 0; st.st_size = 0; ret = fstat(root->fp, &st); ret = fstat(root->fp, &st); if (st.st_size < (*block + 1) * CTREE_BLOCKSIZE) if (st.st_size < (*block + 1) * CTREE_BLOCKSIZE) { ret = ftruncate(root->fp, ret = ftruncate(root->fp, (*block + 1) * CTREE_BLOCKSIZE); (*block + 1) * CTREE_BLOCKSIZE); if (ret) { perror("ftruncate"); exit(1); } } return ret; return ret; } } Loading Loading @@ -81,11 +86,7 @@ struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr) buf = radix_tree_lookup(&root->cache_radix, blocknr); buf = radix_tree_lookup(&root->cache_radix, blocknr); if (buf) { if (buf) { buf->count++; buf->count++; if (buf->blocknr != blocknr) goto test; BUG(); if (buf->blocknr != buf->node.header.blocknr) BUG(); return buf; } } buf = alloc_tree_block(root, blocknr); buf = alloc_tree_block(root, blocknr); if (!buf) if (!buf) Loading @@ -95,8 +96,11 @@ struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr) free(buf); free(buf); return NULL; return NULL; } } test: if (buf->blocknr != buf->node.header.blocknr) if (buf->blocknr != buf->node.header.blocknr) BUG(); BUG(); if (root->node && buf->node.header.parentid != root->node->node.header.parentid) BUG(); return buf; return buf; } } Loading @@ -111,36 +115,30 @@ int write_tree_block(struct ctree_root *root, struct tree_buffer *buf) ret = pwrite(root->fp, &buf->node, CTREE_BLOCKSIZE, offset); ret = pwrite(root->fp, &buf->node, CTREE_BLOCKSIZE, offset); if (ret != CTREE_BLOCKSIZE) if (ret != CTREE_BLOCKSIZE) return ret; return ret; if (buf == root->node) return update_root_block(root); return 0; return 0; } } struct ctree_super_block { struct ctree_root_info root_info; struct ctree_root_info extent_info; } __attribute__ ((__packed__)); static int __setup_root(struct ctree_root *root, struct ctree_root *extent_root, static int __setup_root(struct ctree_root *root, struct ctree_root *extent_root, struct ctree_root_info *info, int fp) struct ctree_root_info *info, int fp) { { INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL); root->fp = fp; root->fp = fp; root->node = NULL; root->node = read_tree_block(root, info->tree_root); root->node = read_tree_block(root, info->tree_root); root->extent_root = extent_root; root->extent_root = extent_root; memcpy(&root->ai1, &info->alloc_extent, sizeof(info->alloc_extent)); memcpy(&root->ai1, &info->alloc_extent, sizeof(info->alloc_extent)); memcpy(&root->ai2, &info->reserve_extent, sizeof(info->reserve_extent)); memcpy(&root->ai2, &info->reserve_extent, sizeof(info->reserve_extent)); root->alloc_extent = &root->ai1; root->alloc_extent = &root->ai1; root->reserve_extent = &root->ai2; root->reserve_extent = &root->ai2; INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL); printf("setup done reading root %p, used %lu available %lu\n", root, root->alloc_extent->num_used, root->alloc_extent->num_blocks); printf("setup done reading root %p, used %lu\n", root, root->alloc_extent->num_used); printf("setup done reading root %p, reserve used %lu available %lu\n", root, root->reserve_extent->num_used, root->reserve_extent->num_blocks); return 0; return 0; } } struct ctree_root *open_ctree(char *filename) struct ctree_root *open_ctree(char *filename, struct ctree_super_block *super) { { struct ctree_root *root = malloc(sizeof(struct ctree_root)); struct ctree_root *root = malloc(sizeof(struct ctree_root)); struct ctree_root *extent_root = malloc(sizeof(struct ctree_root)); struct ctree_root *extent_root = malloc(sizeof(struct ctree_root)); struct ctree_super_block super; int fp; int fp; int ret; int ret; Loading @@ -149,48 +147,61 @@ struct ctree_root *open_ctree(char *filename) free(root); free(root); return NULL; return NULL; } } ret = pread(fp, &super, sizeof(struct ctree_super_block), ret = pread(fp, super, sizeof(struct ctree_super_block), CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); if (ret == 0) { if (ret == 0) { ret = mkfs(fp); ret = mkfs(fp); if (ret) if (ret) return NULL; return NULL; ret = pread(fp, &super, sizeof(struct ctree_super_block), ret = pread(fp, super, sizeof(struct ctree_super_block), CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); if (ret != sizeof(struct ctree_super_block)) if (ret != sizeof(struct ctree_super_block)) return NULL; return NULL; } } BUG_ON(ret < 0); BUG_ON(ret < 0); __setup_root(root, extent_root, &super.root_info, fp); __setup_root(root, extent_root, &super->root_info, fp); __setup_root(extent_root, extent_root, &super.extent_info, fp); __setup_root(extent_root, extent_root, &super->extent_info, fp); return root; return root; } } int close_ctree(struct ctree_root *root) static int __update_root(struct ctree_root *root, struct ctree_root_info *info) { { close(root->fp); info->tree_root = root->node->blocknr; if (root->node) memcpy(&info->alloc_extent, root->alloc_extent, sizeof(struct alloc_extent)); tree_block_release(root, root->node); memcpy(&info->reserve_extent, root->reserve_extent, sizeof(struct alloc_extent)); free(root); printf("on close %d blocks are allocated\n", allocated_blocks); return 0; return 0; } } int update_root_block(struct ctree_root *root) int write_ctree_super(struct ctree_root *root, struct ctree_super_block *s) { { int ret; int ret; u64 root_block = root->node->blocknr; __update_root(root, &s->root_info); __update_root(root->extent_root, &s->extent_info); ret = pwrite(root->fp, &root_block, sizeof(u64), 0); ret = pwrite(root->fp, s, sizeof(*s), CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); if (ret != sizeof(u64)) if (ret != sizeof(*s)) { fprintf(stderr, "failed to write new super block err %d\n", ret); return ret; return ret; } return 0; } int close_ctree(struct ctree_root *root) { close(root->fp); if (root->node) tree_block_release(root, root->node); if (root->extent_root->node) tree_block_release(root->extent_root, root->extent_root->node); free(root); printf("on close %d blocks are allocated\n", allocated_blocks); return 0; return 0; } } void tree_block_release(struct ctree_root *root, struct tree_buffer *buf) void tree_block_release(struct ctree_root *root, struct tree_buffer *buf) { { return; buf->count--; buf->count--; if (buf->count < 0) BUG(); if (buf->count == 0) { if (buf->count == 0) { if (!radix_tree_lookup(&root->cache_radix, buf->blocknr)) if (!radix_tree_lookup(&root->cache_radix, buf->blocknr)) BUG(); BUG(); Loading fs/btrfs/disk-io.h +2 −2 Original line number Original line Diff line number Diff line Loading @@ -12,11 +12,11 @@ struct tree_buffer { struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr); struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr); int write_tree_block(struct ctree_root *root, struct tree_buffer *buf); int write_tree_block(struct ctree_root *root, struct tree_buffer *buf); struct ctree_root *open_ctree(char *filename); struct ctree_root *open_ctree(char *filename, struct ctree_super_block *s); int close_ctree(struct ctree_root *root); int close_ctree(struct ctree_root *root); void tree_block_release(struct ctree_root *root, struct tree_buffer *buf); void tree_block_release(struct ctree_root *root, struct tree_buffer *buf); struct tree_buffer *alloc_free_block(struct ctree_root *root); struct tree_buffer *alloc_free_block(struct ctree_root *root); int update_root_block(struct ctree_root *root); int write_ctree_super(struct ctree_root *root, struct ctree_super_block *s); int mkfs(int fd); int mkfs(int fd); #define CTREE_SUPER_INFO_OFFSET(bs) (16 * (bs)) #define CTREE_SUPER_INFO_OFFSET(bs) (16 * (bs)) Loading fs/btrfs/mkfs.c +5 −2 Original line number Original line Diff line number Diff line Loading @@ -18,12 +18,13 @@ int mkfs(int fd) struct extent_item extent_item; struct extent_item extent_item; int ret; int ret; /* setup the super block area */ memset(info, 0, sizeof(info)); memset(info, 0, sizeof(info)); info[0].blocknr = 16; info[0].blocknr = 16; info[0].objectid = 1; info[0].objectid = 1; info[0].tree_root = 17; info[0].tree_root = 17; info[0].alloc_extent.blocknr = 0; info[0].alloc_extent.blocknr = 0; info[0].alloc_extent.num_blocks = 20; info[0].alloc_extent.num_blocks = 64; /* 0-17 are used (inclusive) */ /* 0-17 are used (inclusive) */ info[0].alloc_extent.num_used = 18; info[0].alloc_extent.num_used = 18; Loading @@ -31,12 +32,14 @@ int mkfs(int fd) info[1].objectid = 2; info[1].objectid = 2; info[1].tree_root = 64; info[1].tree_root = 64; info[1].alloc_extent.blocknr = 64; info[1].alloc_extent.blocknr = 64; info[1].alloc_extent.num_blocks = 8; info[1].alloc_extent.num_blocks = 64; info[1].alloc_extent.num_used = 1; info[1].alloc_extent.num_used = 1; ret = pwrite(fd, info, sizeof(info), ret = pwrite(fd, info, sizeof(info), CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); if (ret != sizeof(info)) if (ret != sizeof(info)) return -1; return -1; /* create leaves for the tree root and extent root */ memset(&empty_leaf, 0, sizeof(empty_leaf)); memset(&empty_leaf, 0, sizeof(empty_leaf)); empty_leaf.header.parentid = 1; empty_leaf.header.parentid = 1; empty_leaf.header.blocknr = 17; empty_leaf.header.blocknr = 17; Loading Loading
fs/btrfs/ctree.c +46 −23 Original line number Original line Diff line number Diff line Loading @@ -354,6 +354,7 @@ int __insert_ptr(struct ctree_root *root, c->header.nritems = 2; c->header.nritems = 2; c->header.flags = node_level(level); c->header.flags = node_level(level); c->header.blocknr = t->blocknr; c->header.blocknr = t->blocknr; c->header.parentid = root->node->node.header.parentid; lower = &path->nodes[level-1]->node; lower = &path->nodes[level-1]->node; if (is_leaf(lower->header.flags)) if (is_leaf(lower->header.flags)) lower_key = &((struct leaf *)lower)->items[0].key; lower_key = &((struct leaf *)lower)->items[0].key; Loading @@ -363,7 +364,7 @@ int __insert_ptr(struct ctree_root *root, memcpy(c->keys + 1, key, sizeof(struct key)); memcpy(c->keys + 1, key, sizeof(struct key)); c->blockptrs[0] = path->nodes[level-1]->blocknr; c->blockptrs[0] = path->nodes[level-1]->blocknr; c->blockptrs[1] = blocknr; c->blockptrs[1] = blocknr; /* the path has an extra ref to root->node */ /* the super has an extra ref to root->node */ tree_block_release(root, root->node); tree_block_release(root, root->node); root->node = t; root->node = t; t->count++; t->count++; Loading Loading @@ -439,6 +440,7 @@ int insert_ptr(struct ctree_root *root, b = &b_buffer->node; b = &b_buffer->node; b->header.flags = c->header.flags; b->header.flags = c->header.flags; b->header.blocknr = b_buffer->blocknr; b->header.blocknr = b_buffer->blocknr; b->header.parentid = root->node->node.header.parentid; mid = (c->header.nritems + 1) / 2; mid = (c->header.nritems + 1) / 2; memcpy(b->keys, c->keys + mid, memcpy(b->keys, c->keys + mid, (c->header.nritems - mid) * sizeof(struct key)); (c->header.nritems - mid) * sizeof(struct key)); Loading Loading @@ -642,6 +644,7 @@ int split_leaf(struct ctree_root *root, struct ctree_path *path, int data_size) right->header.nritems = nritems - mid; right->header.nritems = nritems - mid; right->header.blocknr = right_buffer->blocknr; right->header.blocknr = right_buffer->blocknr; right->header.flags = node_level(0); right->header.flags = node_level(0); right->header.parentid = root->node->node.header.parentid; data_copy_size = l->items[mid].offset + l->items[mid].size - data_copy_size = l->items[mid].offset + l->items[mid].size - leaf_data_end(l); leaf_data_end(l); memcpy(right->items, l->items + mid, memcpy(right->items, l->items + mid, Loading Loading @@ -689,8 +692,12 @@ int insert_item(struct ctree_root *root, struct key *key, unsigned int data_end; unsigned int data_end; struct ctree_path path; struct ctree_path path; refill_alloc_extent(root); /* create a root if there isn't one */ /* create a root if there isn't one */ if (!root->node) { if (!root->node) { BUG(); #if 0 struct tree_buffer *t; struct tree_buffer *t; t = alloc_free_block(root); t = alloc_free_block(root); BUG_ON(!t); BUG_ON(!t); Loading @@ -699,6 +706,7 @@ int insert_item(struct ctree_root *root, struct key *key, t->node.header.blocknr = t->blocknr; t->node.header.blocknr = t->blocknr; root->node = t; root->node = t; write_tree_block(root, t); write_tree_block(root, t); #endif } } init_path(&path); init_path(&path); ret = search_slot(root, key, &path); ret = search_slot(root, key, &path); Loading Loading @@ -758,7 +766,6 @@ int insert_item(struct ctree_root *root, struct key *key, if (leaf_free_space(leaf) < 0) if (leaf_free_space(leaf) < 0) BUG(); BUG(); release_path(root, &path); release_path(root, &path); refill_alloc_extent(root); return 0; return 0; } } Loading Loading @@ -893,7 +900,7 @@ int next_leaf(struct ctree_root *root, struct ctree_path *path) int level = 1; int level = 1; u64 blocknr; u64 blocknr; struct tree_buffer *c; struct tree_buffer *c; struct tree_buffer *next; struct tree_buffer *next = NULL; while(level < MAX_LEVEL) { while(level < MAX_LEVEL) { if (!path->nodes[level]) if (!path->nodes[level]) Loading @@ -905,6 +912,8 @@ int next_leaf(struct ctree_root *root, struct ctree_path *path) continue; continue; } } blocknr = c->node.blockptrs[slot]; blocknr = c->node.blockptrs[slot]; if (next) tree_block_release(root, next); next = read_tree_block(root, blocknr); next = read_tree_block(root, blocknr); break; break; } } Loading @@ -922,7 +931,7 @@ int next_leaf(struct ctree_root *root, struct ctree_path *path) return 0; return 0; } } int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start, int alloc_extent(struct ctree_root *orig_root, u64 num_blocks, u64 search_start, u64 search_end, u64 owner, struct key *ins) u64 search_end, u64 owner, struct key *ins) { { struct ctree_path path; struct ctree_path path; Loading @@ -934,6 +943,7 @@ int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start, int start_found = 0; int start_found = 0; struct leaf *l; struct leaf *l; struct extent_item extent_item; struct extent_item extent_item; struct ctree_root * root = orig_root->extent_root; init_path(&path); init_path(&path); ins->objectid = search_start; ins->objectid = search_start; Loading Loading @@ -974,13 +984,18 @@ int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start, start_found = 1; start_found = 1; last_block = key->objectid + key->offset; last_block = key->objectid + key->offset; path.slots[0]++; path.slots[0]++; printf("last block is not %lu\n", last_block); } } // FIXME -ENOSPC // FIXME -ENOSPC insert: insert: release_path(root, &path); extent_item.refs = 1; extent_item.refs = 1; extent_item.owner = owner; extent_item.owner = owner; ret = insert_item(root, ins, &extent_item, sizeof(extent_item)); if (root == orig_root && root->reserve_extent->num_blocks == 0) { root->reserve_extent->blocknr = ins->objectid; root->reserve_extent->num_blocks = ins->offset; root->reserve_extent->num_used = 0; } ret = insert_item(root->extent_root, ins, &extent_item, sizeof(extent_item)); return ret; return ret; } } Loading @@ -991,7 +1006,6 @@ static int refill_alloc_extent(struct ctree_root *root) int ret; int ret; int min_blocks = MAX_LEVEL * 2; int min_blocks = MAX_LEVEL * 2; printf("refill alloc root %p, numused %lu total %lu\n", root, ae->num_used, ae->num_blocks); if (ae->num_blocks > ae->num_used && ae->num_blocks - ae->num_used > if (ae->num_blocks > ae->num_used && ae->num_blocks - ae->num_used > min_blocks) min_blocks) return 0; return 0; Loading @@ -1007,9 +1021,9 @@ static int refill_alloc_extent(struct ctree_root *root) BUG(); BUG(); return 0; return 0; } } // FIXME, this recurses ret = alloc_extent(root, ret = alloc_extent(root->extent_root, min_blocks * 2, 0, (unsigned long)-1, min_blocks * 2, 0, (unsigned long)-1, 0, &key); root->node->node.header.parentid, &key); ae->blocknr = key.objectid; ae->blocknr = key.objectid; ae->num_blocks = key.offset; ae->num_blocks = key.offset; ae->num_used = 0; ae->num_used = 0; Loading @@ -1021,6 +1035,7 @@ void print_leaf(struct leaf *l) int i; int i; int nr = l->header.nritems; int nr = l->header.nritems; struct item *item; struct item *item; struct extent_item *ei; printf("leaf %lu total ptrs %d free space %d\n", l->header.blocknr, nr, printf("leaf %lu total ptrs %d free space %d\n", l->header.blocknr, nr, leaf_free_space(l)); leaf_free_space(l)); fflush(stdout); fflush(stdout); Loading @@ -1032,6 +1047,8 @@ void print_leaf(struct leaf *l) item->offset, item->size); item->offset, item->size); fflush(stdout); fflush(stdout); printf("\t\titem data %.*s\n", item->size, l->data+item->offset); printf("\t\titem data %.*s\n", item->size, l->data+item->offset); ei = (struct extent_item *)(l->data + item->offset); printf("\t\textent data %u %lu\n", ei->refs, ei->owner); fflush(stdout); fflush(stdout); } } } } Loading Loading @@ -1080,8 +1097,8 @@ void print_tree(struct ctree_root *root, struct tree_buffer *t) /* for testing only */ /* for testing only */ int next_key(int i, int max_key) { int next_key(int i, int max_key) { // return rand() % max_key; return rand() % max_key; return i; // return i; } } int main() { int main() { Loading @@ -1092,15 +1109,20 @@ int main() { int i; int i; int num; int num; int ret; int ret; int run_size = 256; int run_size = 10000; int max_key = 100000000; int max_key = 100000000; int tree_size = 0; int tree_size = 0; struct ctree_path path; struct ctree_path path; struct ctree_super_block super; radix_tree_init(); radix_tree_init(); root = open_ctree("dbfile"); root = open_ctree("dbfile", &super); printf("root tree\n"); print_tree(root, root->node); printf("map tree\n"); print_tree(root->extent_root, root->extent_root->node); srand(55); srand(55); for (i = 0; i < run_size; i++) { for (i = 0; i < run_size; i++) { Loading @@ -1112,22 +1134,20 @@ int main() { ins.objectid = num; ins.objectid = num; ins.offset = 0; ins.offset = 0; ins.flags = 0; ins.flags = 0; printf("insert %d\n", i); ret = insert_item(root, &ins, buf, strlen(buf)); ret = insert_item(root, &ins, buf, strlen(buf)); if (!ret) if (!ret) tree_size++; tree_size++; printf("done insert %d\n", i); } } printf("root used: %lu\n", root->alloc_extent->num_used); printf("root used: %lu\n", root->alloc_extent->num_used); printf("root tree\n"); printf("root tree\n"); print_tree(root, root->node); // print_tree(root, root->node); printf("map tree\n"); printf("map tree\n"); printf("map used: %lu\n", root->extent_root->alloc_extent->num_used); printf("map used: %lu\n", root->extent_root->alloc_extent->num_used); print_tree(root->extent_root, root->extent_root->node); // print_tree(root->extent_root, root->extent_root->node); exit(1); write_ctree_super(root, &super); close_ctree(root); close_ctree(root); root = open_ctree("dbfile"); root = open_ctree("dbfile", &super); printf("starting search\n"); printf("starting search\n"); srand(55); srand(55); for (i = 0; i < run_size; i++) { for (i = 0; i < run_size; i++) { Loading @@ -1142,8 +1162,9 @@ int main() { } } release_path(root, &path); release_path(root, &path); } } write_ctree_super(root, &super); close_ctree(root); close_ctree(root); root = open_ctree("dbfile"); root = open_ctree("dbfile", &super); printf("node %p level %d total ptrs %d free spc %lu\n", root->node, printf("node %p level %d total ptrs %d free spc %lu\n", root->node, node_level(root->node->node.header.flags), node_level(root->node->node.header.flags), root->node->node.header.nritems, root->node->node.header.nritems, Loading Loading @@ -1174,8 +1195,9 @@ int main() { if (!ret) if (!ret) tree_size++; tree_size++; } } write_ctree_super(root, &super); close_ctree(root); close_ctree(root); root = open_ctree("dbfile"); root = open_ctree("dbfile", &super); printf("starting search2\n"); printf("starting search2\n"); srand(128); srand(128); for (i = 0; i < run_size; i++) { for (i = 0; i < run_size; i++) { Loading Loading @@ -1221,6 +1243,7 @@ int main() { } } release_path(root, &path); release_path(root, &path); } } write_ctree_super(root, &super); close_ctree(root); close_ctree(root); printf("tree size is now %d\n", tree_size); printf("tree size is now %d\n", tree_size); return 0; return 0; Loading
fs/btrfs/ctree.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,11 @@ struct ctree_root_info { u64 snapuuid[2]; /* root specific uuid */ u64 snapuuid[2]; /* root specific uuid */ } __attribute__ ((__packed__)); } __attribute__ ((__packed__)); struct ctree_super_block { struct ctree_root_info root_info; struct ctree_root_info extent_info; } __attribute__ ((__packed__)); struct item { struct item { struct key key; struct key key; u16 offset; u16 offset; Loading
fs/btrfs/disk-io.c +45 −34 Original line number Original line Diff line number Diff line Loading @@ -15,7 +15,7 @@ static int allocated_blocks = 0; static int get_free_block(struct ctree_root *root, u64 *block) static int get_free_block(struct ctree_root *root, u64 *block) { { struct stat st; struct stat st; int ret; int ret = 0; if (root->alloc_extent->num_used >= root->alloc_extent->num_blocks) if (root->alloc_extent->num_used >= root->alloc_extent->num_blocks) return -1; return -1; Loading @@ -30,9 +30,14 @@ static int get_free_block(struct ctree_root *root, u64 *block) } } st.st_size = 0; st.st_size = 0; ret = fstat(root->fp, &st); ret = fstat(root->fp, &st); if (st.st_size < (*block + 1) * CTREE_BLOCKSIZE) if (st.st_size < (*block + 1) * CTREE_BLOCKSIZE) { ret = ftruncate(root->fp, ret = ftruncate(root->fp, (*block + 1) * CTREE_BLOCKSIZE); (*block + 1) * CTREE_BLOCKSIZE); if (ret) { perror("ftruncate"); exit(1); } } return ret; return ret; } } Loading Loading @@ -81,11 +86,7 @@ struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr) buf = radix_tree_lookup(&root->cache_radix, blocknr); buf = radix_tree_lookup(&root->cache_radix, blocknr); if (buf) { if (buf) { buf->count++; buf->count++; if (buf->blocknr != blocknr) goto test; BUG(); if (buf->blocknr != buf->node.header.blocknr) BUG(); return buf; } } buf = alloc_tree_block(root, blocknr); buf = alloc_tree_block(root, blocknr); if (!buf) if (!buf) Loading @@ -95,8 +96,11 @@ struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr) free(buf); free(buf); return NULL; return NULL; } } test: if (buf->blocknr != buf->node.header.blocknr) if (buf->blocknr != buf->node.header.blocknr) BUG(); BUG(); if (root->node && buf->node.header.parentid != root->node->node.header.parentid) BUG(); return buf; return buf; } } Loading @@ -111,36 +115,30 @@ int write_tree_block(struct ctree_root *root, struct tree_buffer *buf) ret = pwrite(root->fp, &buf->node, CTREE_BLOCKSIZE, offset); ret = pwrite(root->fp, &buf->node, CTREE_BLOCKSIZE, offset); if (ret != CTREE_BLOCKSIZE) if (ret != CTREE_BLOCKSIZE) return ret; return ret; if (buf == root->node) return update_root_block(root); return 0; return 0; } } struct ctree_super_block { struct ctree_root_info root_info; struct ctree_root_info extent_info; } __attribute__ ((__packed__)); static int __setup_root(struct ctree_root *root, struct ctree_root *extent_root, static int __setup_root(struct ctree_root *root, struct ctree_root *extent_root, struct ctree_root_info *info, int fp) struct ctree_root_info *info, int fp) { { INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL); root->fp = fp; root->fp = fp; root->node = NULL; root->node = read_tree_block(root, info->tree_root); root->node = read_tree_block(root, info->tree_root); root->extent_root = extent_root; root->extent_root = extent_root; memcpy(&root->ai1, &info->alloc_extent, sizeof(info->alloc_extent)); memcpy(&root->ai1, &info->alloc_extent, sizeof(info->alloc_extent)); memcpy(&root->ai2, &info->reserve_extent, sizeof(info->reserve_extent)); memcpy(&root->ai2, &info->reserve_extent, sizeof(info->reserve_extent)); root->alloc_extent = &root->ai1; root->alloc_extent = &root->ai1; root->reserve_extent = &root->ai2; root->reserve_extent = &root->ai2; INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL); printf("setup done reading root %p, used %lu available %lu\n", root, root->alloc_extent->num_used, root->alloc_extent->num_blocks); printf("setup done reading root %p, used %lu\n", root, root->alloc_extent->num_used); printf("setup done reading root %p, reserve used %lu available %lu\n", root, root->reserve_extent->num_used, root->reserve_extent->num_blocks); return 0; return 0; } } struct ctree_root *open_ctree(char *filename) struct ctree_root *open_ctree(char *filename, struct ctree_super_block *super) { { struct ctree_root *root = malloc(sizeof(struct ctree_root)); struct ctree_root *root = malloc(sizeof(struct ctree_root)); struct ctree_root *extent_root = malloc(sizeof(struct ctree_root)); struct ctree_root *extent_root = malloc(sizeof(struct ctree_root)); struct ctree_super_block super; int fp; int fp; int ret; int ret; Loading @@ -149,48 +147,61 @@ struct ctree_root *open_ctree(char *filename) free(root); free(root); return NULL; return NULL; } } ret = pread(fp, &super, sizeof(struct ctree_super_block), ret = pread(fp, super, sizeof(struct ctree_super_block), CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); if (ret == 0) { if (ret == 0) { ret = mkfs(fp); ret = mkfs(fp); if (ret) if (ret) return NULL; return NULL; ret = pread(fp, &super, sizeof(struct ctree_super_block), ret = pread(fp, super, sizeof(struct ctree_super_block), CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); if (ret != sizeof(struct ctree_super_block)) if (ret != sizeof(struct ctree_super_block)) return NULL; return NULL; } } BUG_ON(ret < 0); BUG_ON(ret < 0); __setup_root(root, extent_root, &super.root_info, fp); __setup_root(root, extent_root, &super->root_info, fp); __setup_root(extent_root, extent_root, &super.extent_info, fp); __setup_root(extent_root, extent_root, &super->extent_info, fp); return root; return root; } } int close_ctree(struct ctree_root *root) static int __update_root(struct ctree_root *root, struct ctree_root_info *info) { { close(root->fp); info->tree_root = root->node->blocknr; if (root->node) memcpy(&info->alloc_extent, root->alloc_extent, sizeof(struct alloc_extent)); tree_block_release(root, root->node); memcpy(&info->reserve_extent, root->reserve_extent, sizeof(struct alloc_extent)); free(root); printf("on close %d blocks are allocated\n", allocated_blocks); return 0; return 0; } } int update_root_block(struct ctree_root *root) int write_ctree_super(struct ctree_root *root, struct ctree_super_block *s) { { int ret; int ret; u64 root_block = root->node->blocknr; __update_root(root, &s->root_info); __update_root(root->extent_root, &s->extent_info); ret = pwrite(root->fp, &root_block, sizeof(u64), 0); ret = pwrite(root->fp, s, sizeof(*s), CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); if (ret != sizeof(u64)) if (ret != sizeof(*s)) { fprintf(stderr, "failed to write new super block err %d\n", ret); return ret; return ret; } return 0; } int close_ctree(struct ctree_root *root) { close(root->fp); if (root->node) tree_block_release(root, root->node); if (root->extent_root->node) tree_block_release(root->extent_root, root->extent_root->node); free(root); printf("on close %d blocks are allocated\n", allocated_blocks); return 0; return 0; } } void tree_block_release(struct ctree_root *root, struct tree_buffer *buf) void tree_block_release(struct ctree_root *root, struct tree_buffer *buf) { { return; buf->count--; buf->count--; if (buf->count < 0) BUG(); if (buf->count == 0) { if (buf->count == 0) { if (!radix_tree_lookup(&root->cache_radix, buf->blocknr)) if (!radix_tree_lookup(&root->cache_radix, buf->blocknr)) BUG(); BUG(); Loading
fs/btrfs/disk-io.h +2 −2 Original line number Original line Diff line number Diff line Loading @@ -12,11 +12,11 @@ struct tree_buffer { struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr); struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr); int write_tree_block(struct ctree_root *root, struct tree_buffer *buf); int write_tree_block(struct ctree_root *root, struct tree_buffer *buf); struct ctree_root *open_ctree(char *filename); struct ctree_root *open_ctree(char *filename, struct ctree_super_block *s); int close_ctree(struct ctree_root *root); int close_ctree(struct ctree_root *root); void tree_block_release(struct ctree_root *root, struct tree_buffer *buf); void tree_block_release(struct ctree_root *root, struct tree_buffer *buf); struct tree_buffer *alloc_free_block(struct ctree_root *root); struct tree_buffer *alloc_free_block(struct ctree_root *root); int update_root_block(struct ctree_root *root); int write_ctree_super(struct ctree_root *root, struct ctree_super_block *s); int mkfs(int fd); int mkfs(int fd); #define CTREE_SUPER_INFO_OFFSET(bs) (16 * (bs)) #define CTREE_SUPER_INFO_OFFSET(bs) (16 * (bs)) Loading
fs/btrfs/mkfs.c +5 −2 Original line number Original line Diff line number Diff line Loading @@ -18,12 +18,13 @@ int mkfs(int fd) struct extent_item extent_item; struct extent_item extent_item; int ret; int ret; /* setup the super block area */ memset(info, 0, sizeof(info)); memset(info, 0, sizeof(info)); info[0].blocknr = 16; info[0].blocknr = 16; info[0].objectid = 1; info[0].objectid = 1; info[0].tree_root = 17; info[0].tree_root = 17; info[0].alloc_extent.blocknr = 0; info[0].alloc_extent.blocknr = 0; info[0].alloc_extent.num_blocks = 20; info[0].alloc_extent.num_blocks = 64; /* 0-17 are used (inclusive) */ /* 0-17 are used (inclusive) */ info[0].alloc_extent.num_used = 18; info[0].alloc_extent.num_used = 18; Loading @@ -31,12 +32,14 @@ int mkfs(int fd) info[1].objectid = 2; info[1].objectid = 2; info[1].tree_root = 64; info[1].tree_root = 64; info[1].alloc_extent.blocknr = 64; info[1].alloc_extent.blocknr = 64; info[1].alloc_extent.num_blocks = 8; info[1].alloc_extent.num_blocks = 64; info[1].alloc_extent.num_used = 1; info[1].alloc_extent.num_used = 1; ret = pwrite(fd, info, sizeof(info), ret = pwrite(fd, info, sizeof(info), CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); if (ret != sizeof(info)) if (ret != sizeof(info)) return -1; return -1; /* create leaves for the tree root and extent root */ memset(&empty_leaf, 0, sizeof(empty_leaf)); memset(&empty_leaf, 0, sizeof(empty_leaf)); empty_leaf.header.parentid = 1; empty_leaf.header.parentid = 1; empty_leaf.header.blocknr = 17; empty_leaf.header.blocknr = 17; Loading