superblock duplication
authorYan Zheng <zheng.yan@oracle.com>
Fri, 5 Dec 2008 17:21:31 +0000 (12:21 -0500)
committerChris Mason <chris.mason@oracle.com>
Fri, 5 Dec 2008 17:21:31 +0000 (12:21 -0500)
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 <zheng.yan@oracle.com>
disk-io.c
disk-io.h
extent-tree.c
mkfs.c
utils.c
volumes.c
volumes.h

index 497a6db61f0404204fe9a78403e30ba1715cc494..46662c5c1890d107c0459714bedfbb7baaf5f796 100644 (file)
--- 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;
index 5b827e4fc0f1c95b783c9ae8cbb6d1866a88f1c3..8e9fab9d4520a301564f8d32d45704ddaa0b0cf1 100644 (file)
--- a/disk-io.h
+++ b/disk-io.h
 #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,
index 6a5194c5ebede6c286734ddbabc56ce7c5d78da9..b4ae95a9c62f4d27c4b6592c52cb308151507060 100644 (file)
@@ -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 cc0eec02172c66181976ad0cdfd854b4ad2cd429..f942dc738e867a617d656d3bc528e1f706e86e65 100644 (file)
--- 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 766368936afd6529b8ab4dab0dfdeffbb425527f..b6b34ea4ae2faf77d935c7390941e9fbfa54b496 100644 (file)
--- 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) {
index a5519930aa420793e580e23ffe052f15065fe4dc..c261847960441cb2a8e950734849530059e7c063 100644 (file)
--- 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),
index ad8cfaf375a8fb2d4fabc3b25cdef30bd086308c..bb787517ec02ac8c2bbe5ea2bafd9b120d91d53f 100644 (file)
--- 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,