Write all super blocks during commit
authorChris Mason <chris.mason@oracle.com>
Thu, 10 Apr 2008 20:22:00 +0000 (16:22 -0400)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Thu, 10 Apr 2008 20:22:00 +0000 (16:22 -0400)
disk-io.c
disk-io.h
utils.c
volumes.c
volumes.h

index 8150d73..6896bd7 100644 (file)
--- 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;
index 1b5cbdf..bd8ca63 100644 (file)
--- 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 (file)
--- 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;
 }
 
index 44e6729..2997567 100644 (file)
--- 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) {
index be54316..b6edc54 100644 (file)
--- 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