summaryrefslogtreecommitdiff
path: root/volumes.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-04-10 16:22:00 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2008-04-10 16:22:00 -0400
commitd1b04c21120aa55cc737b8a1ddcdf31cefb97b97 (patch)
tree1c192fbf849fb8f03ed1dd69074842273c93b97f /volumes.c
parentfd2d0af0bf80c127fbb3b84817a420fbc490da5d (diff)
Write all super blocks during commit
Diffstat (limited to 'volumes.c')
-rw-r--r--volumes.c64
1 files changed, 62 insertions, 2 deletions
diff --git a/volumes.c b/volumes.c
index 44e67291..29975672 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) {