From 5ccd1715fa2eaad0b26037bb53706779c8c93b5f Mon Sep 17 00:00:00 2001 From: Yan Zheng Date: Fri, 5 Dec 2008 12:21:31 -0500 Subject: superblock duplication This patch updates btrfs-progs for superblock duplication. Note: I didn't make this patch as complete as the one for kernel since updating the converter requires changing the code again. Thank you, Signed-off-by: Yan Zheng --- disk-io.c | 33 ++++++++++++++++++++++------ disk-io.h | 13 ++++++++++- extent-tree.c | 26 ++++++++++++++++++++++ mkfs.c | 7 ++++-- utils.c | 26 +++++++++------------- volumes.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++---------- volumes.h | 3 +++ 7 files changed, 140 insertions(+), 37 deletions(-) diff --git a/disk-io.c b/disk-io.c index 497a6db6..46662c5c 100644 --- a/disk-io.c +++ b/disk-io.c @@ -607,8 +607,6 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, ret = btrfs_open_devices(fs_devices, O_RDONLY); BUG_ON(ret); - ret = btrfs_bootstrap_super_map(&fs_info->mapping_tree, fs_devices); - BUG_ON(ret); fs_info->sb_buffer = btrfs_find_create_tree_block(tree_root, sb_bytenr, 4096); BUG_ON(!fs_info->sb_buffer); @@ -697,6 +695,31 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, return root; } +int write_dev_supers(struct btrfs_root *root, struct extent_buffer *sb, + struct btrfs_device *device) +{ + u64 bytenr; + u64 flags; + int i, ret; + + sb->fd = device->fd; + for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { + bytenr = btrfs_sb_offset(i); + if (bytenr + BTRFS_SUPER_INFO_SIZE >= device->total_bytes) + break; + + btrfs_set_header_bytenr(sb, bytenr); + flags = btrfs_header_flags(sb); + btrfs_set_header_flags(sb, flags | BTRFS_HEADER_FLAG_WRITTEN); + csum_tree_block(root, sb, 0); + + sb->dev_bytenr = bytenr; + ret = write_extent_to_disk(sb); + BUG_ON(ret); + } + return 0; +} + int write_all_supers(struct btrfs_root *root) { struct list_head *cur; @@ -728,11 +751,7 @@ int write_all_supers(struct btrfs_root *root) write_extent_buffer(sb, dev->fs_devices->fsid, (unsigned long)btrfs_device_fsid(dev_item), BTRFS_UUID_SIZE); - sb->fd = dev->fd; - sb->dev_bytenr = sb->start; - btrfs_set_header_flag(sb, BTRFS_HEADER_FLAG_WRITTEN); - csum_tree_block(root, sb, 0); - ret = write_extent_to_disk(sb); + ret = write_dev_supers(root, sb, dev); BUG_ON(ret); } return 0; diff --git a/disk-io.h b/disk-io.h index 5b827e4f..8e9fab9d 100644 --- a/disk-io.h +++ b/disk-io.h @@ -19,9 +19,20 @@ #ifndef __DISKIO__ #define __DISKIO__ -#define BTRFS_SUPER_INFO_OFFSET (16 * 1024) +#define BTRFS_SUPER_INFO_OFFSET (64 * 1024) #define BTRFS_SUPER_INFO_SIZE 4096 +#define BTRFS_SUPER_MIRROR_MAX 3 +#define BTRFS_SUPER_MIRROR_SHIFT 12 + +static inline u64 btrfs_sb_offset(int mirror) +{ + u64 start = 16 * 1024; + if (mirror) + return start << (BTRFS_SUPER_MIRROR_SHIFT * mirror); + return BTRFS_SUPER_INFO_OFFSET; +} + struct btrfs_device; struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, diff --git a/extent-tree.c b/extent-tree.c index 6a5194c5..b4ae95a9 100644 --- a/extent-tree.c +++ b/extent-tree.c @@ -61,6 +61,31 @@ void maybe_unlock_mutex(struct btrfs_root *root) { } +static int remove_sb_from_cache(struct btrfs_root *root, + struct btrfs_block_group_cache *cache) +{ + u64 bytenr; + u64 *logical; + int stripe_len; + int i, nr, ret; + struct extent_io_tree *free_space_cache; + + free_space_cache = &root->fs_info->free_space_cache; + for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { + bytenr = btrfs_sb_offset(i); + ret = btrfs_rmap_block(&root->fs_info->mapping_tree, + cache->key.objectid, bytenr, 0, + &logical, &nr, &stripe_len); + BUG_ON(ret); + while (nr--) { + clear_extent_dirty(free_space_cache, logical[nr], + logical[nr] + stripe_len - 1, GFP_NOFS); + } + kfree(logical); + } + return 0; +} + static int cache_block_group(struct btrfs_root *root, struct btrfs_block_group_cache *block_group) { @@ -153,6 +178,7 @@ next: set_extent_dirty(free_space_cache, last, last + hole_size - 1, GFP_NOFS); } + remove_sb_from_cache(root, block_group); block_group->cached = 1; err: btrfs_free_path(path); diff --git a/mkfs.c b/mkfs.c index cc0eec02..f942dc73 100644 --- a/mkfs.c +++ b/mkfs.c @@ -414,8 +414,11 @@ int main(int ac, char **av) if (block_count == 0) block_count = dev_block_count; - for (i = 0; i < 7; i++) - blocks[i] = BTRFS_SUPER_INFO_OFFSET + leafsize * i; + blocks[0] = BTRFS_SUPER_INFO_OFFSET; + for (i = 1; i < 7; i++) { + blocks[i] = BTRFS_SUPER_INFO_OFFSET + 1024 * 1024 + + leafsize * i; + } ret = make_btrfs(fd, file, label, blocks, block_count, nodesize, leafsize, diff --git a/utils.c b/utils.c index 76636893..b6b34ea4 100644 --- a/utils.c +++ b/utils.c @@ -194,18 +194,7 @@ int make_btrfs(int fd, const char *device, const char *label, /* create the items for the extent tree */ nritems = 0; - itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - - sizeof(struct btrfs_extent_item); - btrfs_set_disk_key_objectid(&disk_key, 0); - btrfs_set_disk_key_offset(&disk_key, first_free); - btrfs_set_disk_key_type(&disk_key, BTRFS_EXTENT_ITEM_KEY); - btrfs_set_item_key(buf, &disk_key, nritems); - btrfs_set_item_offset(buf, btrfs_item_nr(buf, nritems), itemoff); - btrfs_set_item_size(buf, btrfs_item_nr(buf, nritems), - sizeof(struct btrfs_extent_item)); - extent_item = btrfs_item_ptr(buf, nritems, struct btrfs_extent_item); - btrfs_set_extent_refs(buf, extent_item, 1); - nritems++; + itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize); for (i = 1; i < 7; i++) { BUG_ON(blocks[i] < first_free); BUG_ON(blocks[i] < blocks[i - 1]); @@ -517,17 +506,15 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, kfree(buf); list_add(&device->dev_list, &root->fs_info->fs_devices->devices); device->fs_devices = root->fs_info->fs_devices; - ret = btrfs_bootstrap_super_map(&root->fs_info->mapping_tree, - root->fs_info->fs_devices); - BUG_ON(ret); return 0; } int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret) { u64 block_count; + u64 bytenr; struct stat st; - int ret; + int i, ret; ret = fstat(fd, &st); if (ret < 0) { @@ -552,6 +539,13 @@ int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret) exit(1); } + for (i = 0 ; i < BTRFS_SUPER_MIRROR_MAX; i++) { + bytenr = btrfs_sb_offset(i); + if (bytenr >= block_count) + break; + zero_blocks(fd, bytenr, BTRFS_SUPER_INFO_SIZE); + } + if (zero_end) { ret = zero_dev_end(fd, block_count); if (ret) { diff --git a/volumes.c b/volumes.c index a5519930..c2618479 100644 --- a/volumes.c +++ b/volumes.c @@ -888,6 +888,62 @@ int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len) return ret; } +int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, + u64 chunk_start, u64 physical, u64 devid, + u64 **logical, int *naddrs, int *stripe_len) +{ + struct cache_extent *ce; + struct map_lookup *map; + u64 *buf; + u64 bytenr; + u64 length; + u64 stripe_nr; + int i, j, nr = 0; + + ce = find_first_cache_extent(&map_tree->cache_tree, chunk_start); + BUG_ON(!ce || ce->start != chunk_start); + map = container_of(ce, struct map_lookup, ce); + + length = ce->size; + if (map->type & BTRFS_BLOCK_GROUP_RAID10) + length = ce->size / (map->num_stripes / map->sub_stripes); + else if (map->type & BTRFS_BLOCK_GROUP_RAID0) + length = ce->size / map->num_stripes; + + buf = kzalloc(sizeof(u64) * map->num_stripes, GFP_NOFS); + + for (i = 0; i < map->num_stripes; i++) { + if (devid && map->stripes[i].dev->devid != devid) + continue; + if (map->stripes[i].physical > physical || + map->stripes[i].physical + length <= physical) + continue; + + stripe_nr = (physical - map->stripes[i].physical) / + map->stripe_len; + + if (map->type & BTRFS_BLOCK_GROUP_RAID10) { + stripe_nr = (stripe_nr * map->num_stripes + i) / + map->sub_stripes; + } else if (map->type & BTRFS_BLOCK_GROUP_RAID0) { + stripe_nr = stripe_nr * map->num_stripes + i; + } + bytenr = chunk_start + stripe_nr * map->stripe_len; + for (j = 0; j < nr; j++) { + if (buf[j] == bytenr) + break; + } + if (j == nr) + buf[nr++] = bytenr; + } + + *logical = buf; + *naddrs = nr; + *stripe_len = map->stripe_len; + + return 0; +} + int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, u64 logical, u64 *length, struct btrfs_multi_bio **multi_ret, int mirror_num) @@ -1000,7 +1056,6 @@ again: } BUG_ON(stripe_index >= map->num_stripes); - BUG_ON(stripe_index != 0 && multi->num_stripes > 1); for (i = 0; i < multi->num_stripes; i++) { multi->stripes[i].physical = map->stripes[stripe_index].physical + stripe_offset + @@ -1118,7 +1173,6 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, u64 logical; u64 length; u64 devid; - u64 super_offset_diff = 0; u8 uuid[BTRFS_UUID_SIZE]; int num_stripes; int ret; @@ -1127,12 +1181,6 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, logical = key->offset; length = btrfs_chunk_length(leaf, chunk); - if (logical < BTRFS_SUPER_INFO_OFFSET + BTRFS_SUPER_INFO_SIZE) { - super_offset_diff = BTRFS_SUPER_INFO_OFFSET + - BTRFS_SUPER_INFO_SIZE - logical; - logical = BTRFS_SUPER_INFO_OFFSET + BTRFS_SUPER_INFO_SIZE; - } - ce = find_first_cache_extent(&map_tree->cache_tree, logical); /* already mapped? */ @@ -1146,7 +1194,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, return -ENOMEM; map->ce.start = logical; - map->ce.size = length - super_offset_diff; + map->ce.size = length; map->num_stripes = num_stripes; map->io_width = btrfs_chunk_io_width(leaf, chunk); map->io_align = btrfs_chunk_io_align(leaf, chunk); @@ -1157,8 +1205,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, for (i = 0; i < num_stripes; i++) { map->stripes[i].physical = - btrfs_stripe_offset_nr(leaf, chunk, i) + - super_offset_diff; + btrfs_stripe_offset_nr(leaf, chunk, i); devid = btrfs_stripe_devid_nr(leaf, chunk, i); read_extent_buffer(leaf, uuid, (unsigned long) btrfs_stripe_dev_uuid_nr(chunk, i), diff --git a/volumes.h b/volumes.h index ad8cfaf3..bb787517 100644 --- a/volumes.h +++ b/volumes.h @@ -99,6 +99,9 @@ int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, u64 logical, u64 *length, struct btrfs_multi_bio **multi_ret, int mirror_num); +int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, + u64 chunk_start, u64 physical, u64 devid, + u64 **logical, int *naddrs, int *stripe_len); int btrfs_read_sys_array(struct btrfs_root *root); int btrfs_read_chunk_tree(struct btrfs_root *root); int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, -- cgit v1.2.3