Btrfs: add a device id to device items
authorChris Mason <chris.mason@oracle.com>
Thu, 12 Apr 2007 16:14:00 +0000 (12:14 -0400)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Thu, 12 Apr 2007 16:14:00 +0000 (12:14 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/super.c

index 454eb88611bb57109c9cc2b73d92c8e191c2397f..ef3583cf74d6d4a836ff019680a07126a510d22d 100644 (file)
@@ -91,10 +91,12 @@ struct btrfs_super_block {
        __le64 total_blocks;
        __le64 blocks_used;
        __le64 root_dir_objectid;
+       __le64 last_device_id;
        /* fields below here vary with the underlying disk */
        __le64 device_block_start;
        __le64 device_num_blocks;
        __le64 device_root;
+       __le64 device_id;
 } __attribute__ ((__packed__));
 
 /*
@@ -230,6 +232,7 @@ struct btrfs_csum_item {
 
 struct btrfs_device_item {
        __le16 pathlen;
+       __le64 device_id;
 } __attribute__ ((__packed__));
 
 struct crypto_hash;
@@ -798,6 +801,28 @@ static inline void btrfs_set_super_root_dir(struct btrfs_super_block *s, u64
        s->root_dir_objectid = cpu_to_le64(val);
 }
 
+static inline u64 btrfs_super_last_device_id(struct btrfs_super_block *s)
+{
+       return le64_to_cpu(s->last_device_id);
+}
+
+static inline void btrfs_set_super_last_device_id(struct btrfs_super_block *s,
+                                                 u64 val)
+{
+       s->last_device_id = cpu_to_le64(val);
+}
+
+static inline u64 btrfs_super_device_id(struct btrfs_super_block *s)
+{
+       return le64_to_cpu(s->device_id);
+}
+
+static inline void btrfs_set_super_device_id(struct btrfs_super_block *s,
+                                                 u64 val)
+{
+       s->device_id = cpu_to_le64(val);
+}
+
 static inline u64 btrfs_super_device_block_start(struct btrfs_super_block *s)
 {
        return le64_to_cpu(s->device_block_start);
@@ -910,6 +935,17 @@ static inline void btrfs_set_device_pathlen(struct btrfs_device_item *d,
        d->pathlen = cpu_to_le16(val);
 }
 
+static inline u64 btrfs_device_id(struct btrfs_device_item *d)
+{
+       return le64_to_cpu(d->device_id);
+}
+
+static inline void btrfs_set_device_id(struct btrfs_device_item *d,
+                                               u64 val)
+{
+       d->device_id = cpu_to_le64(val);
+}
+
 static inline struct btrfs_root *btrfs_sb(struct super_block *sb)
 {
        return sb->s_fs_info;
index 3ba4df20c913fe77ac910cec7fb369ae29081370..06b969c14625a4abba280ea318d5f181ee4c20ed 100644 (file)
 struct dev_lookup {
        u64 block_start;
        u64 num_blocks;
+       u64 device_id;
        struct block_device *bdev;
 };
 
 int btrfs_insert_dev_radix(struct btrfs_root *root,
                           struct block_device *bdev,
+                          u64 device_id,
                           u64 block_start,
                           u64 num_blocks)
 {
@@ -31,6 +33,7 @@ int btrfs_insert_dev_radix(struct btrfs_root *root,
        lookup->block_start = block_start;
        lookup->num_blocks = num_blocks;
        lookup->bdev = bdev;
+       lookup->device_id = device_id;
 printk("inserting %s into dev radix %Lu %Lu\n", bdevname(bdev, b), block_start, num_blocks);
 
        ret = radix_tree_insert(&root->fs_info->dev_radix, block_start +
@@ -418,17 +421,14 @@ printk("all worked\n");
        return root;
 }
 
-int btrfs_open_disk(struct btrfs_root *root, u64 block_start, u64 num_blocks,
-                   char *filename, int name_len)
+static int btrfs_open_disk(struct btrfs_root *root, u64 device_id,
+                          u64 block_start, u64 num_blocks,
+                          char *filename, int name_len)
 {
        char *null_filename;
        struct block_device *bdev;
        int ret;
 
-       if (block_start == 0) {
-printk("skipping disk with block_start == 0\n");
-return 0;
-       }
        null_filename = kmalloc(name_len + 1, GFP_NOFS);
        if (!null_filename)
                return -ENOMEM;
@@ -441,7 +441,8 @@ return 0;
                goto out;
        }
        set_blocksize(bdev, root->fs_info->sb->s_blocksize);
-       ret = btrfs_insert_dev_radix(root, bdev, block_start, num_blocks);
+       ret = btrfs_insert_dev_radix(root, bdev, device_id,
+                                    block_start, num_blocks);
        BUG_ON(ret);
        ret = 0;
 out:
@@ -490,10 +491,14 @@ static int read_device_info(struct btrfs_root *root)
                }
                dev_item = btrfs_item_ptr(leaf, slot, struct btrfs_device_item);
 printk("found key %Lu %Lu\n", key.objectid, key.offset);
-               ret = btrfs_open_disk(root, key.objectid, key.offset,
-                                     (char *)(dev_item + 1),
-                                     btrfs_device_pathlen(dev_item));
-               BUG_ON(ret);
+               if (btrfs_device_id(dev_item) !=
+                   btrfs_super_device_id(root->fs_info->disk_super)) {
+                       ret = btrfs_open_disk(root, btrfs_device_id(dev_item),
+                                             key.objectid, key.offset,
+                                             (char *)(dev_item + 1),
+                                             btrfs_device_pathlen(dev_item));
+                       BUG_ON(ret);
+               }
                path->slots[0]++;
        }
        btrfs_free_path(path);
@@ -556,6 +561,7 @@ struct btrfs_root *open_ctree(struct super_block *sb)
        dev_lookup->block_start = 0;
        dev_lookup->num_blocks = (u32)-2;
        dev_lookup->bdev = sb->s_bdev;
+       dev_lookup->device_id = 0;
        ret = radix_tree_insert(&fs_info->dev_radix, (u32)-2, dev_lookup);
        BUG_ON(ret);
        fs_info->sb_buffer = read_tree_block(tree_root,
@@ -575,6 +581,8 @@ struct btrfs_root *open_ctree(struct super_block *sb)
        radix_tree_delete(&fs_info->dev_radix, (u32)-2);
        dev_lookup->block_start = btrfs_super_device_block_start(disk_super);
        dev_lookup->num_blocks = btrfs_super_device_num_blocks(disk_super);
+       dev_lookup->device_id = btrfs_super_device_id(disk_super);
+
        ret = radix_tree_insert(&fs_info->dev_radix,
                                dev_lookup->block_start +
                                dev_lookup->num_blocks - 1, dev_lookup);
@@ -659,6 +667,7 @@ int del_fs_roots(struct btrfs_fs_info *fs_info)
        }
        return 0;
 }
+
 static int free_dev_radix(struct btrfs_fs_info *fs_info)
 {
        struct dev_lookup *lookup[8];
index aa9f56c3841901c75f974db17ab1df9ff1242e2e..444ebb0141aea35c072d1fd1486b999e8ea3a75e 100644 (file)
@@ -44,6 +44,7 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
 u64 bh_blocknr(struct buffer_head *bh);
 int btrfs_insert_dev_radix(struct btrfs_root *root,
                           struct block_device *bdev,
+                          u64 device_id,
                           u64 block_start,
                           u64 num_blocks);
 int btrfs_map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh,
index c46d7eafcf6270d1eda4af056893d76378185efb..8dcf600e39efe487bb600d5b3e92445f55a04fb8 100644 (file)
@@ -1840,7 +1840,9 @@ static int add_disk(struct btrfs_root *root, char *name, int namelen)
        u16 item_size;
        u64 num_blocks;
        u64 new_blocks;
+       u64 device_id;
        int ret;
+
 printk("adding disk %s\n", name);
        path = btrfs_alloc_path();
        if (!path)
@@ -1875,9 +1877,14 @@ printk("insert failed %d\n", ret);
                                  path->slots[0], struct btrfs_device_item);
        btrfs_set_device_pathlen(dev_item, namelen);
        memcpy(dev_item + 1, name, namelen);
+
+       device_id = btrfs_super_last_device_id(root->fs_info->disk_super) + 1;
+       btrfs_set_super_last_device_id(root->fs_info->disk_super, device_id);
+       btrfs_set_device_id(dev_item, device_id);
        mark_buffer_dirty(path->nodes[0]);
 
-       ret = btrfs_insert_dev_radix(root, bdev, num_blocks, new_blocks);
+       ret = btrfs_insert_dev_radix(root, bdev, device_id, num_blocks,
+                                    new_blocks);
 
        if (!ret) {
                btrfs_set_super_total_blocks(root->fs_info->disk_super,