From d1b04c21120aa55cc737b8a1ddcdf31cefb97b97 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 10 Apr 2008 16:22:00 -0400 Subject: [PATCH] Write all super blocks during commit --- disk-io.c | 41 ++++++++++++++++++++++++++++++++++++++-- disk-io.h | 2 ++ utils.c | 3 +++ volumes.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- volumes.h | 2 ++ 5 files changed, 108 insertions(+), 4 deletions(-) diff --git a/disk-io.c b/disk-io.c index 8150d73..6896bd7 100644 --- a/disk-io.c +++ b/disk-io.c @@ -195,6 +195,7 @@ int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, length = eb->len; ret = btrfs_map_block(&root->fs_info->mapping_tree, WRITE, eb->start, &length, &multi, 0); + while(dev_nr < multi->num_stripes) { BUG_ON(ret); eb->fd = multi->stripes[dev_nr].dev->fd; @@ -528,10 +529,12 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr) ret = btrfs_open_devices(fs_devices, O_RDWR); 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); - fs_info->sb_buffer->fd = fs_devices->lowest_bdev; + fs_info->sb_buffer->fd = fs_devices->latest_bdev; fs_info->sb_buffer->dev_bytenr = sb_bytenr; ret = read_extent_from_disk(fs_info->sb_buffer); BUG_ON(ret); @@ -608,6 +611,40 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr) return root; } +int write_all_supers(struct btrfs_root *root) +{ + struct list_head *cur; + struct list_head *head = &root->fs_info->fs_devices->devices; + struct btrfs_device *dev; + struct extent_buffer *sb; + struct btrfs_dev_item *dev_item; + int ret; + + sb = root->fs_info->sb_buffer; + dev_item = (struct btrfs_dev_item *)offsetof(struct btrfs_super_block, + dev_item); + list_for_each(cur, head) { + dev = list_entry(cur, struct btrfs_device, dev_list); + btrfs_set_device_type(sb, dev_item, dev->type); + btrfs_set_device_id(sb, dev_item, dev->devid); + btrfs_set_device_total_bytes(sb, dev_item, dev->total_bytes); + btrfs_set_device_bytes_used(sb, dev_item, dev->bytes_used); + btrfs_set_device_io_align(sb, dev_item, dev->io_align); + btrfs_set_device_io_width(sb, dev_item, dev->io_width); + btrfs_set_device_sector_size(sb, dev_item, dev->sector_size); + write_extent_buffer(sb, dev->uuid, + (unsigned long)btrfs_device_uuid(dev_item), + BTRFS_DEV_UUID_SIZE); + sb->fd = dev->fd; + sb->dev_bytenr = BTRFS_SUPER_INFO_OFFSET; + btrfs_set_header_flag(sb, BTRFS_HEADER_FLAG_WRITTEN); + csum_tree_block(root, sb, 0); + ret = write_extent_to_disk(sb); + BUG_ON(ret); + } + return 0; +} + int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root) { @@ -627,7 +664,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans, write_extent_buffer(root->fs_info->sb_buffer, &root->fs_info->super_copy, 0, sizeof(root->fs_info->super_copy)); - ret = write_tree_block(trans, root, root->fs_info->sb_buffer); + ret = write_all_supers(root); if (ret) fprintf(stderr, "failed to write new super block err %d\n", ret); return ret; diff --git a/disk-io.h b/disk-io.h index 1b5cbdf..bd8ca63 100644 --- a/disk-io.h +++ b/disk-io.h @@ -20,6 +20,8 @@ #define __DISKIO__ #define BTRFS_SUPER_INFO_OFFSET (16 * 1024) +#define BTRFS_SUPER_INFO_SIZE 4096 + struct btrfs_device; struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, diff --git a/utils.c b/utils.c index 9d162da..0015ee2 100644 --- a/utils.c +++ b/utils.c @@ -471,6 +471,9 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, kfree(buf); list_add(&device->dev_list, &root->fs_info->fs_devices->devices); + ret = btrfs_bootstrap_super_map(&root->fs_info->mapping_tree, + root->fs_info->fs_devices); + BUG_ON(ret); return 0; } diff --git a/volumes.c b/volumes.c index 44e6729..2997567 100644 --- a/volumes.c +++ b/volumes.c @@ -862,6 +862,57 @@ struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid) return __find_device(head, devid); } +int btrfs_bootstrap_super_map(struct btrfs_mapping_tree *map_tree, + struct btrfs_fs_devices *fs_devices) +{ + struct map_lookup *map; + u64 logical = BTRFS_SUPER_INFO_OFFSET; + u64 length = BTRFS_SUPER_INFO_SIZE; + int num_stripes = 0; + int ret; + int i; + struct list_head *cur; + + list_for_each(cur, &fs_devices->devices) { + num_stripes++; + } + map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); + if (!map) + return -ENOMEM; + + map->ce.start = logical; + map->ce.size = length; + map->num_stripes = num_stripes; + map->io_width = length; + map->io_align = length; + map->sector_size = length; + map->stripe_len = length; + map->type = BTRFS_BLOCK_GROUP_RAID1; + + i = 0; + list_for_each(cur, &fs_devices->devices) { + struct btrfs_device *device = list_entry(cur, + struct btrfs_device, + dev_list); + map->stripes[i].physical = logical; + map->stripes[i].dev = device; + i++; + } + ret = insert_existing_cache_extent(&map_tree->cache_tree, &map->ce); + if (ret == -EEXIST) { + struct cache_extent *old; + struct map_lookup *old_map; + old = find_cache_extent(&map_tree->cache_tree, logical, length); + old_map = container_of(old, struct map_lookup, ce); + remove_cache_extent(&map_tree->cache_tree, old); + kfree(old_map); + ret = insert_existing_cache_extent(&map_tree->cache_tree, + &map->ce); + } + BUG_ON(ret); + return 0; +} + static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, struct extent_buffer *leaf, struct btrfs_chunk *chunk) @@ -872,12 +923,20 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, u64 logical; u64 length; u64 devid; + u64 super_offset_diff = 0; int num_stripes; int ret; int i; logical = key->objectid; length = key->offset; + + 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? */ @@ -891,7 +950,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, return -ENOMEM; map->ce.start = logical; - map->ce.size = length; + map->ce.size = length - super_offset_diff; map->num_stripes = num_stripes; map->io_width = btrfs_chunk_io_width(leaf, chunk); map->io_align = btrfs_chunk_io_align(leaf, chunk); @@ -901,7 +960,8 @@ 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); + btrfs_stripe_offset_nr(leaf, chunk, i) + + super_offset_diff; devid = btrfs_stripe_devid_nr(leaf, chunk, i); map->stripes[i].dev = btrfs_find_device(root, devid); if (!map->stripes[i].dev) { diff --git a/volumes.h b/volumes.h index be54316..b6edc54 100644 --- a/volumes.h +++ b/volumes.h @@ -105,4 +105,6 @@ int btrfs_scan_one_device(int fd, const char *path, struct btrfs_fs_devices **fs_devices_ret, u64 *total_devs, u64 super_offset); int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len); +int btrfs_bootstrap_super_map(struct btrfs_mapping_tree *map_tree, + struct btrfs_fs_devices *fs_devices); #endif -- 2.7.4