From 3eaaf935e56e03e3c1db110f055c756bd3415c88 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 12 Apr 2007 12:14:47 -0400 Subject: [PATCH] add some support for multiple devices to progs --- ctree.h | 37 ++++++++++ disk-io.c | 196 +++++++++++++++++++++++++++++++++++++++++++++++++-- disk-io.h | 2 + mkfs.c | 5 +- print-tree.c | 3 +- 5 files changed, 235 insertions(+), 8 deletions(-) diff --git a/ctree.h b/ctree.h index edd965f3..fb1f5d51 100644 --- a/ctree.h +++ b/ctree.h @@ -87,10 +87,12 @@ struct btrfs_super_block { __le64 total_blocks; __le64 blocks_used; __le64 root_dir_objectid; + __le64 last_device_id; /* fields below here vary with the underlying disk */ __le64 device_block_start; __le64 device_num_blocks; __le64 device_root; + __le64 device_id; } __attribute__ ((__packed__)); /* @@ -226,6 +228,7 @@ struct btrfs_csum_item { struct btrfs_device_item { __le16 pathlen; + __le64 device_id; } __attribute__ ((__packed__)); struct btrfs_fs_info { @@ -237,6 +240,7 @@ struct btrfs_fs_info { struct btrfs_key last_insert; struct radix_tree_root cache_radix; struct radix_tree_root pinned_radix; + struct radix_tree_root dev_radix; struct list_head trans; struct list_head cache; u64 last_inode_alloc; @@ -785,6 +789,28 @@ static inline void btrfs_set_super_root_dir(struct btrfs_super_block *s, u64 s->root_dir_objectid = cpu_to_le64(val); } +static inline u64 btrfs_super_last_device_id(struct btrfs_super_block *s) +{ + return le64_to_cpu(s->last_device_id); +} + +static inline void btrfs_set_super_last_device_id(struct btrfs_super_block *s, + u64 val) +{ + s->last_device_id = cpu_to_le64(val); +} + +static inline u64 btrfs_super_device_id(struct btrfs_super_block *s) +{ + return le64_to_cpu(s->device_id); +} + +static inline void btrfs_set_super_device_id(struct btrfs_super_block *s, + u64 val) +{ + s->device_id = cpu_to_le64(val); +} + static inline u64 btrfs_super_device_block_start(struct btrfs_super_block *s) { return le64_to_cpu(s->device_block_start); @@ -896,6 +922,17 @@ static inline void btrfs_set_device_pathlen(struct btrfs_device_item *d, d->pathlen = cpu_to_le16(val); } +static inline u64 btrfs_device_id(struct btrfs_device_item *d) +{ + return le64_to_cpu(d->device_id); +} + +static inline void btrfs_set_device_id(struct btrfs_device_item *d, + u64 val) +{ + d->device_id = cpu_to_le64(val); +} + /* helper function to cast into the data area of the leaf. */ #define btrfs_item_ptr(leaf, slot, type) \ ((type *)(btrfs_leaf_data(leaf) + \ diff --git a/disk-io.c b/disk-io.c index dff3bd57..49bda148 100644 --- a/disk-io.c +++ b/disk-io.c @@ -14,6 +14,60 @@ static int allocated_blocks = 0; int cache_max = 10000; +struct dev_lookup { + u64 block_start; + u64 num_blocks; + u64 device_id; + int fd; +}; + +int btrfs_insert_dev_radix(struct btrfs_root *root, + int fd, + u64 device_id, + u64 block_start, + u64 num_blocks) +{ + struct dev_lookup *lookup; + int ret; + + lookup = malloc(sizeof(*lookup)); + if (!lookup) + return -ENOMEM; + lookup->block_start = block_start; + lookup->num_blocks = num_blocks; + lookup->fd = fd; + lookup->device_id = device_id; +printf("inserting into dev radix %Lu %Lu\n", block_start, num_blocks); + + ret = radix_tree_insert(&root->fs_info->dev_radix, block_start + + num_blocks - 1, lookup); + return ret; +} + +int btrfs_map_bh_to_logical(struct btrfs_root *root, struct btrfs_buffer *bh, + u64 logical) +{ + struct dev_lookup *lookup[2]; + + int ret; + + root = root->fs_info->dev_root; + ret = radix_tree_gang_lookup(&root->fs_info->dev_radix, + (void **)lookup, + (unsigned long)logical, + ARRAY_SIZE(lookup)); + if (ret == 0 || lookup[0]->block_start > logical || + lookup[0]->block_start + lookup[0]->num_blocks <= logical) { + ret = -1; + goto out; + } + bh->fd = lookup[0]->fd; + bh->dev_blocknr = logical - lookup[0]->block_start; + ret = 0; +out: + return ret; +} + static int check_tree_block(struct btrfs_root *root, struct btrfs_buffer *buf) { if (buf->blocknr != btrfs_header_blocknr(&buf->node.header)) @@ -86,7 +140,6 @@ struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 blocknr) struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr) { - loff_t offset = blocknr * root->blocksize; struct btrfs_buffer *buf; int ret; buf = radix_tree_lookup(&root->fs_info->cache_radix, blocknr); @@ -96,8 +149,9 @@ struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr) buf = alloc_tree_block(root, blocknr); if (!buf) return NULL; - ret = pread(root->fs_info->fp, &buf->node, root->blocksize, - offset); + btrfs_map_bh_to_logical(root, buf, blocknr); + ret = pread(buf->fd, &buf->node, root->blocksize, + buf->dev_blocknr * root->blocksize); if (ret != root->blocksize) { free(buf); return NULL; @@ -131,13 +185,13 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_buffer *buf) { - u64 blocknr = buf->blocknr; - loff_t offset = blocknr * root->blocksize; int ret; if (buf->blocknr != btrfs_header_blocknr(&buf->node.header)) BUG(); - ret = pwrite(root->fs_info->fp, &buf->node, root->blocksize, offset); + btrfs_map_bh_to_logical(root, buf, buf->blocknr); + ret = pwrite(buf->fd, &buf->node, root->blocksize, + buf->dev_blocknr * root->blocksize); if (ret != root->blocksize) return ret; return 0; @@ -169,6 +223,11 @@ static int commit_tree_roots(struct btrfs_trans_handle *trans, struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *extent_root = fs_info->extent_root; + if (btrfs_super_device_root(fs_info->disk_super) != + fs_info->dev_root->node->blocknr) { + btrfs_set_super_device_root(fs_info->disk_super, + fs_info->dev_root->node->blocknr); + } while(1) { old_extent_block = btrfs_root_blocknr(&extent_root->root_item); if (old_extent_block == extent_root->node->blocknr) @@ -257,6 +316,86 @@ static int find_and_setup_root(struct btrfs_super_block *super, return 0; } +int btrfs_open_disk(struct btrfs_root *root, u64 device_id, + u64 block_start, u64 num_blocks, + char *filename, int name_len) +{ + char *null_filename; + int fd; + int ret; + + null_filename = malloc(name_len + 1); + if (!null_filename) + return -ENOMEM; + memcpy(null_filename, filename, name_len); + null_filename[name_len] = '\0'; + + fd = open(null_filename, O_RDWR); + if (fd < 0) { + ret = -1; + goto out; + } + ret = btrfs_insert_dev_radix(root, fd, device_id, + block_start, num_blocks); + BUG_ON(ret); + ret = 0; +out: + free(null_filename); + return ret; +} + +static int read_device_info(struct btrfs_root *root) +{ + struct btrfs_path path; + int ret; + struct btrfs_key key; + struct btrfs_leaf *leaf; + struct btrfs_device_item *dev_item; + int nritems; + int slot; + + root = root->fs_info->dev_root; + + btrfs_init_path(&path); + key.objectid = 0; + key.offset = 0; + key.flags = 0; + btrfs_set_key_type(&key, BTRFS_DEV_ITEM_KEY); + + ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); + leaf = &path.nodes[0]->leaf; + nritems = btrfs_header_nritems(&leaf->header); + while(1) { + slot = path.slots[0]; + if (slot >= nritems) { + ret = btrfs_next_leaf(root, &path); + if (ret) + break; + leaf = &path.nodes[0]->leaf; + nritems = btrfs_header_nritems(&leaf->header); + slot = path.slots[0]; + } + btrfs_disk_key_to_cpu(&key, &leaf->items[slot].key); + if (btrfs_key_type(&key) != BTRFS_DEV_ITEM_KEY) { + path.slots[0]++; + continue; + } + dev_item = btrfs_item_ptr(leaf, slot, struct btrfs_device_item); + if (btrfs_device_id(dev_item) != + btrfs_super_device_id(root->fs_info->disk_super)) { +printf("found key %Lu %Lu\n", key.objectid, key.offset); + ret = btrfs_open_disk(root, btrfs_device_id(dev_item), + key.objectid, key.offset, + (char *)(dev_item + 1), + btrfs_device_pathlen(dev_item)); + BUG_ON(ret); + } + path.slots[0]++; + } + btrfs_release_path(root, &path); + return 0; +} + struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) { int fp; @@ -275,10 +414,12 @@ struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super) struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root)); struct btrfs_root *dev_root = malloc(sizeof(struct btrfs_root)); struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info)); + struct dev_lookup *dev_lookup; int ret; INIT_RADIX_TREE(&fs_info->cache_radix, GFP_KERNEL); INIT_RADIX_TREE(&fs_info->pinned_radix, GFP_KERNEL); + INIT_RADIX_TREE(&fs_info->dev_radix, GFP_KERNEL); INIT_LIST_HEAD(&fs_info->trans); INIT_LIST_HEAD(&fs_info->cache); fs_info->cache_size = 0; @@ -302,9 +443,23 @@ struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super) } BUG_ON(ret < 0); __setup_root(super, dev_root, fs_info, BTRFS_DEV_TREE_OBJECTID, fp); + + dev_lookup = malloc(sizeof(*dev_lookup)); + dev_lookup->fd = fp; + dev_lookup->device_id = btrfs_super_device_id(super); + dev_lookup->block_start = btrfs_super_device_block_start(super); + dev_lookup->num_blocks = btrfs_super_device_num_blocks(super); + ret = radix_tree_insert(&fs_info->dev_radix, + dev_lookup->block_start + + dev_lookup->num_blocks - 1, dev_lookup); + BUG_ON(ret); + dev_root->node = read_tree_block(dev_root, btrfs_super_device_root(super)); + ret = read_device_info(dev_root); + BUG_ON(ret); + __setup_root(super, tree_root, fs_info, BTRFS_ROOT_TREE_OBJECTID, fp); tree_root->node = read_tree_block(tree_root, btrfs_super_root(super)); BUG_ON(!tree_root->node); @@ -349,6 +504,31 @@ static int drop_cache(struct btrfs_root *root) } return 0; } + +static int free_dev_radix(struct btrfs_fs_info *fs_info) +{ + struct dev_lookup *lookup[8]; + int ret; + int i; + while(1) { + ret = radix_tree_gang_lookup(&fs_info->dev_radix, + (void **)lookup, 0, + ARRAY_SIZE(lookup)); + if (!ret) + break; + for (i = 0; i < ret; i++) { + if (lookup[i]->device_id != + btrfs_super_device_id(fs_info->disk_super)) + close(lookup[i]->fd); + radix_tree_delete(&fs_info->dev_radix, + lookup[i]->block_start + + lookup[i]->num_blocks - 1); + free(lookup[i]); + } + } + return 0; +} + int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s) { int ret; @@ -364,6 +544,7 @@ int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s) drop_cache(root); BUG_ON(!list_empty(&root->fs_info->trans)); + free_dev_radix(root->fs_info); close(root->fs_info->fp); if (root->node) btrfs_block_release(root, root->node); @@ -373,6 +554,9 @@ int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s) if (root->fs_info->tree_root->node) btrfs_block_release(root->fs_info->tree_root, root->fs_info->tree_root->node); + if (root->fs_info->dev_root->node) + btrfs_block_release(root->fs_info->dev_root, + root->fs_info->dev_root->node); btrfs_block_release(root, root->commit_root); free(root); printf("on close %d blocks are allocated\n", allocated_blocks); diff --git a/disk-io.h b/disk-io.h index 21f353a3..87cf36bc 100644 --- a/disk-io.h +++ b/disk-io.h @@ -4,7 +4,9 @@ struct btrfs_buffer { u64 blocknr; + u64 dev_blocknr; int count; + int fd; struct list_head dirty; struct list_head cache; union { diff --git a/mkfs.c b/mkfs.c index 58e754b8..86cbd098 100644 --- a/mkfs.c +++ b/mkfs.c @@ -120,10 +120,12 @@ int mkfs(int fd, char *pathname, u64 num_blocks, u32 blocksize) strcpy((char *)(&super.magic), BTRFS_MAGIC); btrfs_set_super_blocksize(&super, blocksize); btrfs_set_super_total_blocks(&super, num_blocks); - btrfs_set_super_blocks_used(&super, start_block + 4); + btrfs_set_super_blocks_used(&super, start_block + 5); btrfs_set_super_device_block_start(&super, 0); btrfs_set_super_device_num_blocks(&super, num_blocks); btrfs_set_super_device_root(&super, start_block + 2); + btrfs_set_super_device_id(&super, 1); + btrfs_set_super_last_device_id(&super, 1); uuid_generate(super.fsid); block = malloc(blocksize); @@ -188,6 +190,7 @@ int mkfs(int fd, char *pathname, u64 num_blocks, u32 blocksize) btrfs_set_item_offset(&item, itemoff); btrfs_set_item_size(&item, item_size); btrfs_set_device_pathlen(&dev_item, strlen(pathname)); + btrfs_set_device_id(&dev_item, 1); memcpy(empty_leaf->items, &item, sizeof(item)); memcpy(btrfs_leaf_data(empty_leaf) + itemoff, &dev_item, sizeof(dev_item)); diff --git a/print-tree.c b/print-tree.c index eb0c86b0..0250d333 100644 --- a/print-tree.c +++ b/print-tree.c @@ -88,7 +88,8 @@ void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l) break; case BTRFS_DEV_ITEM_KEY: devi = btrfs_item_ptr(l, i, struct btrfs_device_item); - printf("\t\tdev namelen %u name %.*s\n", + printf("\t\tdev id %Lu namelen %u name %.*s\n", + btrfs_device_id(devi), btrfs_device_pathlen(devi), btrfs_device_pathlen(devi), (char *)(devi + 1));