Btrfs: Add support for device scanning and detection ioctls
authorChris Mason <chris.mason@oracle.com>
Mon, 24 Mar 2008 19:02:07 +0000 (15:02 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:04:01 +0000 (11:04 -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/ioctl.h
fs/btrfs/super.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h

index acf22ad6115cc8e62322ca36afa28c1008c177e6..7556f8319c604a20b8eb1b304fce9869d7dedaf4 100644 (file)
@@ -37,7 +37,7 @@ extern struct kmem_cache *btrfs_transaction_cachep;
 extern struct kmem_cache *btrfs_bit_radix_cachep;
 extern struct kmem_cache *btrfs_path_cachep;
 
-#define BTRFS_MAGIC "_B4RfS_M"
+#define BTRFS_MAGIC "_B5RfS_M"
 
 #define BTRFS_MAX_LEVEL 8
 
@@ -238,6 +238,7 @@ struct btrfs_super_block {
        __le64 total_bytes;
        __le64 bytes_used;
        __le64 root_dir_objectid;
+       __le64 num_devices;
        __le32 sectorsize;
        __le32 nodesize;
        __le32 leafsize;
@@ -440,6 +441,7 @@ struct btrfs_block_group_cache {
 };
 
 struct btrfs_device;
+struct btrfs_fs_devices;
 struct btrfs_fs_info {
        u8 fsid[BTRFS_FSID_SIZE];
        struct btrfs_root *extent_root;
@@ -489,7 +491,7 @@ struct btrfs_fs_info {
        u64 total_pinned;
        struct list_head dirty_cowonly_roots;
 
-       struct list_head devices;
+       struct btrfs_fs_devices *fs_devices;
        struct list_head space_info;
        spinlock_t delalloc_lock;
        spinlock_t new_trans_lock;
@@ -677,6 +679,19 @@ BTRFS_SETGET_FUNCS(device_io_width, struct btrfs_dev_item, io_width, 32);
 BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32);
 BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64);
 
+BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item,
+                        total_bytes, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_device_bytes_used, struct btrfs_dev_item,
+                        bytes_used, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_device_io_align, struct btrfs_dev_item,
+                        io_align, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_device_io_width, struct btrfs_dev_item,
+                        io_width, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_device_sector_size, struct btrfs_dev_item,
+                        sector_size, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_device_id, struct btrfs_dev_item, devid, 64);
+
 static inline char *btrfs_device_uuid(struct btrfs_dev_item *d)
 {
        return (char *)d + offsetof(struct btrfs_dev_item, uuid);
@@ -1106,6 +1121,8 @@ BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block,
                         stripesize, 32);
 BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block,
                         root_dir_objectid, 64);
+BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block,
+                        num_devices, 64);
 
 static inline unsigned long btrfs_leaf_data(struct extent_buffer *l)
 {
index 4890151cd68d6143357857b2351ee6c1f831ad56..f971a29e4f20b62d5f0c58ac3dd9895d73b09917 100644 (file)
@@ -365,12 +365,12 @@ static int close_all_devices(struct btrfs_fs_info *fs_info)
        struct list_head *next;
        struct btrfs_device *device;
 
-       list = &fs_info->devices;
-       while(!list_empty(list)) {
-               next = list->next;
-               list_del(next);
+       list = &fs_info->fs_devices->devices;
+       list_for_each(next, list) {
                device = list_entry(next, struct btrfs_device, dev_list);
-               kfree(device);
+               if (device->bdev && device->bdev != fs_info->sb->s_bdev)
+                       close_bdev_excl(device->bdev);
+               device->bdev = NULL;
        }
        return 0;
 }
@@ -655,7 +655,8 @@ static int add_hasher(struct btrfs_fs_info *info, char *type) {
        return 0;
 }
 #endif
-struct btrfs_root *open_ctree(struct super_block *sb)
+struct btrfs_root *open_ctree(struct super_block *sb,
+                             struct btrfs_fs_devices *fs_devices)
 {
        u32 sectorsize;
        u32 nodesize;
@@ -697,8 +698,8 @@ struct btrfs_root *open_ctree(struct super_block *sb)
        fs_info->extent_root = extent_root;
        fs_info->chunk_root = chunk_root;
        fs_info->dev_root = dev_root;
+       fs_info->fs_devices = fs_devices;
        INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
-       INIT_LIST_HEAD(&fs_info->devices);
        INIT_LIST_HEAD(&fs_info->space_info);
        btrfs_mapping_init(&fs_info->mapping_tree);
        fs_info->sb = sb;
@@ -779,6 +780,12 @@ struct btrfs_root *open_ctree(struct super_block *sb)
        if (!btrfs_super_root(disk_super))
                goto fail_sb_buffer;
 
+       if (btrfs_super_num_devices(disk_super) != fs_devices->num_devices) {
+               printk("Btrfs: wanted %llu devices, but found %llu\n",
+                      (unsigned long long)btrfs_super_num_devices(disk_super),
+                      (unsigned long long)fs_devices->num_devices);
+               goto fail_sb_buffer;
+       }
        nodesize = btrfs_super_nodesize(disk_super);
        leafsize = btrfs_super_leafsize(disk_super);
        sectorsize = btrfs_super_sectorsize(disk_super);
@@ -799,8 +806,6 @@ struct btrfs_root *open_ctree(struct super_block *sb)
        }
 
        mutex_lock(&fs_info->fs_mutex);
-       ret = btrfs_read_super_device(tree_root, fs_info->sb_buffer);
-       BUG_ON(ret);
 
        ret = btrfs_read_sys_array(tree_root);
        BUG_ON(ret);
@@ -859,6 +864,7 @@ fail_sb_buffer:
 fail_iput:
        iput(fs_info->btree_inode);
 fail:
+       close_all_devices(fs_info);
        kfree(extent_root);
        kfree(tree_root);
        kfree(fs_info);
index 206cb48638f70edec1542a561091a20399d60ac8..b7cbc58a555300badf7600e6be075c3dbd04e828 100644 (file)
@@ -21,6 +21,7 @@
 
 #define BTRFS_SUPER_INFO_OFFSET (16 * 1024)
 struct btrfs_device;
+struct btrfs_fs_devices;
 
 struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
                                      u32 blocksize);
@@ -29,7 +30,8 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
                                                   u64 bytenr, u32 blocksize);
 int clean_tree_block(struct btrfs_trans_handle *trans,
                     struct btrfs_root *root, struct extent_buffer *buf);
-struct btrfs_root *open_ctree(struct super_block *sb);
+struct btrfs_root *open_ctree(struct super_block *sb,
+                             struct btrfs_fs_devices *fs_devices);
 int close_ctree(struct btrfs_root *root);
 int write_ctree_super(struct btrfs_trans_handle *trans,
                      struct btrfs_root *root);
index 8c6290665d49799a115c364116203f46b97ea970..4551e82013c8ecf99f7ce4382d2720f84e1221c9 100644 (file)
 
 #define BTRFS_IOCTL_MAGIC 0x94
 #define BTRFS_VOL_NAME_MAX 255
+#define BTRFS_PATH_NAME_MAX 4095
+
 struct btrfs_ioctl_vol_args {
-       char name[BTRFS_VOL_NAME_MAX + 1];
+       char name[BTRFS_PATH_NAME_MAX + 1];
 };
 
 #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
@@ -32,4 +34,6 @@ struct btrfs_ioctl_vol_args {
                                   struct btrfs_ioctl_vol_args)
 #define BTRFS_IOC_RESIZE _IOW(BTRFS_IOCTL_MAGIC, 3, \
                                   struct btrfs_ioctl_vol_args)
+#define BTRFS_IOC_SCAN_DEV _IOW(BTRFS_IOCTL_MAGIC, 4, \
+                                  struct btrfs_ioctl_vol_args)
 #endif
index 67ed216df4755c750c3d27f4fe4259710f80ea67..9624923a33dc03f8006988d3f63aa72d49ff90f8 100644 (file)
@@ -44,6 +44,7 @@
 #include "ioctl.h"
 #include "print-tree.h"
 #include "xattr.h"
+#include "volumes.h"
 
 #define BTRFS_SUPER_MAGIC 0x9123683E
 
@@ -216,7 +217,9 @@ static int parse_options (char * options,
        return 1;
 }
 
-static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
+static int btrfs_fill_super(struct super_block * sb,
+                           struct btrfs_fs_devices *fs_devices,
+                           void * data, int silent)
 {
        struct inode * inode;
        struct dentry * root_dentry;
@@ -231,7 +234,7 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
        sb->s_xattr = btrfs_xattr_handlers;
        sb->s_time_gran = 1;
 
-       tree_root = open_ctree(sb);
+       tree_root = open_ctree(sb, fs_devices);
 
        if (!tree_root || IS_ERR(tree_root)) {
                printk("btrfs: open_ctree failed\n");
@@ -334,18 +337,23 @@ static int test_bdev_super(struct super_block *s, void *data)
 
 int btrfs_get_sb_bdev(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data,
-       int (*fill_super)(struct super_block *, void *, int),
        struct vfsmount *mnt, const char *subvol)
 {
        struct block_device *bdev = NULL;
        struct super_block *s;
        struct dentry *root;
+       struct btrfs_fs_devices *fs_devices = NULL;
        int error = 0;
 
-       bdev = open_bdev_excl(dev_name, flags, fs_type);
-       if (IS_ERR(bdev))
-               return PTR_ERR(bdev);
+       error = btrfs_scan_one_device(dev_name, flags, fs_type, &fs_devices);
+       if (error)
+               return error;
 
+       error = btrfs_open_devices(fs_devices, flags, fs_type);
+       if (error)
+               return error;
+
+       bdev = fs_devices->lowest_bdev;
        /*
         * once the super is inserted into the list by sget, s_umount
         * will protect the lockfs code from trying to start a snapshot
@@ -372,7 +380,8 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type,
                s->s_flags = flags;
                strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
                sb_set_blocksize(s, block_size(bdev));
-               error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+               error = btrfs_fill_super(s, fs_devices, data,
+                                        flags & MS_SILENT ? 1 : 0);
                if (error) {
                        up_write(&s->s_umount);
                        deactivate_super(s);
@@ -408,7 +417,7 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type,
 error_s:
        error = PTR_ERR(s);
 error_bdev:
-       close_bdev_excl(bdev);
+       btrfs_close_devices(fs_devices);
 error:
        return error;
 }
@@ -421,8 +430,7 @@ static int btrfs_get_sb(struct file_system_type *fs_type,
        char *subvol_name = NULL;
 
        parse_options((char *)data, NULL, &subvol_name);
-       ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data,
-                       btrfs_fill_super, mnt,
+       ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data, mnt,
                        subvol_name ? subvol_name : "default");
        if (subvol_name)
                kfree(subvol_name);
@@ -445,13 +453,6 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0;
 }
 
-static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
-                               unsigned long arg)
-{
-       printk("btrfs control ioctl %d\n", cmd);
-       return 0;
-}
-
 static struct file_system_type btrfs_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "btrfs",
@@ -460,6 +461,31 @@ static struct file_system_type btrfs_fs_type = {
        .fs_flags       = FS_REQUIRES_DEV,
 };
 
+static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       struct btrfs_ioctl_vol_args *vol;
+       struct btrfs_fs_devices *fs_devices;
+       int ret;
+       int len;
+
+       vol = kmalloc(sizeof(*vol), GFP_KERNEL);
+       if (copy_from_user(vol, (void __user *)arg, sizeof(*vol))) {
+               ret = -EFAULT;
+               goto out;
+       }
+       len = strnlen(vol->name, BTRFS_PATH_NAME_MAX);
+       switch (cmd) {
+       case BTRFS_IOC_SCAN_DEV:
+               ret = btrfs_scan_one_device(vol->name, MS_RDONLY,
+                                           &btrfs_fs_type, &fs_devices);
+               break;
+       }
+out:
+       kfree(vol);
+       return 0;
+}
+
 static void btrfs_write_super_lockfs(struct super_block *sb)
 {
        struct btrfs_root *root = btrfs_sb(sb);
@@ -567,6 +593,7 @@ static void __exit exit_btrfs_fs(void)
        btrfs_interface_exit();
        unregister_filesystem(&btrfs_fs_type);
        btrfs_exit_sysfs();
+       btrfs_cleanup_fs_uuids();
 }
 
 module_init(init_btrfs_fs)
index 16fb6bbe6e289206fa8364553ec686fbdb359360..263f01cc3db40be828b90d2954737656d4e4e8cb 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include <linux/sched.h>
 #include <linux/bio.h>
+#include <linux/buffer_head.h>
 #include "ctree.h"
 #include "extent_map.h"
 #include "disk-io.h"
@@ -28,6 +29,215 @@ struct map_lookup {
        struct btrfs_device *dev;
        u64 physical;
 };
+static DEFINE_MUTEX(uuid_mutex);
+static LIST_HEAD(fs_uuids);
+
+int btrfs_cleanup_fs_uuids(void)
+{
+       struct btrfs_fs_devices *fs_devices;
+       struct list_head *uuid_cur;
+       struct list_head *devices_cur;
+       struct btrfs_device *dev;
+
+       list_for_each(uuid_cur, &fs_uuids) {
+               fs_devices = list_entry(uuid_cur, struct btrfs_fs_devices,
+                                       list);
+               while(!list_empty(&fs_devices->devices)) {
+                       devices_cur = fs_devices->devices.next;
+                       dev = list_entry(devices_cur, struct btrfs_device,
+                                        dev_list);
+                       printk("uuid cleanup finds %s\n", dev->name);
+                       if (dev->bdev) {
+                               printk("closing\n");
+                               close_bdev_excl(dev->bdev);
+                       }
+                       list_del(&dev->dev_list);
+                       kfree(dev);
+               }
+       }
+       return 0;
+}
+
+static struct btrfs_device *__find_device(struct list_head *head, u64 devid)
+{
+       struct btrfs_device *dev;
+       struct list_head *cur;
+
+       list_for_each(cur, head) {
+               dev = list_entry(cur, struct btrfs_device, dev_list);
+               if (dev->devid == devid)
+                       return dev;
+       }
+       return NULL;
+}
+
+static struct btrfs_fs_devices *find_fsid(u8 *fsid)
+{
+       struct list_head *cur;
+       struct btrfs_fs_devices *fs_devices;
+
+       list_for_each(cur, &fs_uuids) {
+               fs_devices = list_entry(cur, struct btrfs_fs_devices, list);
+               if (memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE) == 0)
+                       return fs_devices;
+       }
+       return NULL;
+}
+
+static int device_list_add(const char *path,
+                          struct btrfs_super_block *disk_super,
+                          u64 devid, struct btrfs_fs_devices **fs_devices_ret)
+{
+       struct btrfs_device *device;
+       struct btrfs_fs_devices *fs_devices;
+       u64 found_transid = btrfs_super_generation(disk_super);
+
+       fs_devices = find_fsid(disk_super->fsid);
+       if (!fs_devices) {
+               fs_devices = kmalloc(sizeof(*fs_devices), GFP_NOFS);
+               if (!fs_devices)
+                       return -ENOMEM;
+               INIT_LIST_HEAD(&fs_devices->devices);
+               list_add(&fs_devices->list, &fs_uuids);
+               memcpy(fs_devices->fsid, disk_super->fsid, BTRFS_FSID_SIZE);
+               fs_devices->latest_devid = devid;
+               fs_devices->latest_trans = found_transid;
+               fs_devices->lowest_devid = (u64)-1;
+               fs_devices->num_devices = 0;
+               device = NULL;
+       } else {
+               device = __find_device(&fs_devices->devices, devid);
+       }
+       if (!device) {
+               device = kzalloc(sizeof(*device), GFP_NOFS);
+               if (!device) {
+                       /* we can safely leave the fs_devices entry around */
+                       return -ENOMEM;
+               }
+               device->devid = devid;
+               device->name = kstrdup(path, GFP_NOFS);
+               if (!device->name) {
+                       kfree(device);
+                       return -ENOMEM;
+               }
+               list_add(&device->dev_list, &fs_devices->devices);
+               fs_devices->num_devices++;
+       }
+
+       if (found_transid > fs_devices->latest_trans) {
+               fs_devices->latest_devid = devid;
+               fs_devices->latest_trans = found_transid;
+       }
+       if (fs_devices->lowest_devid > devid) {
+               fs_devices->lowest_devid = devid;
+               printk("lowest devid now %Lu\n", devid);
+       }
+       *fs_devices_ret = fs_devices;
+       return 0;
+}
+
+int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
+{
+       struct list_head *head = &fs_devices->devices;
+       struct list_head *cur;
+       struct btrfs_device *device;
+
+       mutex_lock(&uuid_mutex);
+       list_for_each(cur, head) {
+               device = list_entry(cur, struct btrfs_device, dev_list);
+               if (device->bdev) {
+                       close_bdev_excl(device->bdev);
+                       printk("close devices closes %s\n", device->name);
+               }
+               device->bdev = NULL;
+       }
+       mutex_unlock(&uuid_mutex);
+       return 0;
+}
+
+int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
+                      int flags, void *holder)
+{
+       struct block_device *bdev;
+       struct list_head *head = &fs_devices->devices;
+       struct list_head *cur;
+       struct btrfs_device *device;
+       int ret;
+
+       mutex_lock(&uuid_mutex);
+       list_for_each(cur, head) {
+               device = list_entry(cur, struct btrfs_device, dev_list);
+               bdev = open_bdev_excl(device->name, flags, holder);
+printk("opening %s devid %Lu\n", device->name, device->devid);
+               if (IS_ERR(bdev)) {
+                       printk("open %s failed\n", device->name);
+                       ret = PTR_ERR(bdev);
+                       goto fail;
+               }
+               if (device->devid == fs_devices->latest_devid)
+                       fs_devices->latest_bdev = bdev;
+               if (device->devid == fs_devices->lowest_devid) {
+                       fs_devices->lowest_bdev = bdev;
+printk("lowest bdev %s\n", device->name);
+               }
+               device->bdev = bdev;
+       }
+       mutex_unlock(&uuid_mutex);
+       return 0;
+fail:
+       mutex_unlock(&uuid_mutex);
+       btrfs_close_devices(fs_devices);
+       return ret;
+}
+
+int btrfs_scan_one_device(const char *path, int flags, void *holder,
+                         struct btrfs_fs_devices **fs_devices_ret)
+{
+       struct btrfs_super_block *disk_super;
+       struct block_device *bdev;
+       struct buffer_head *bh;
+       int ret;
+       u64 devid;
+
+       mutex_lock(&uuid_mutex);
+
+       printk("scan one opens %s\n", path);
+       bdev = open_bdev_excl(path, flags, holder);
+
+       if (IS_ERR(bdev)) {
+               printk("open failed\n");
+               ret = PTR_ERR(bdev);
+               goto error;
+       }
+
+       ret = set_blocksize(bdev, 4096);
+       if (ret)
+               goto error_close;
+       bh = __bread(bdev, BTRFS_SUPER_INFO_OFFSET / 4096, 4096);
+       if (!bh) {
+               ret = -EIO;
+               goto error_close;
+       }
+       disk_super = (struct btrfs_super_block *)bh->b_data;
+       if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC,
+           sizeof(disk_super->magic))) {
+               printk("no btrfs found on %s\n", path);
+               ret = -ENOENT;
+               goto error_brelse;
+       }
+       devid = le64_to_cpu(disk_super->dev_item.devid);
+       printk("found device %Lu on %s\n", devid, path);
+       ret = device_list_add(path, disk_super, devid, fs_devices_ret);
+
+error_brelse:
+       brelse(bh);
+error_close:
+       close_bdev_excl(bdev);
+       printk("scan one closes bdev %s\n", path);
+error:
+       mutex_unlock(&uuid_mutex);
+       return ret;
+}
 
 /*
  * this uses a pretty simple search, the expectation is that it is
@@ -56,6 +266,10 @@ static int find_free_dev_extent(struct btrfs_trans_handle *trans,
 
        /* FIXME use last free of some kind */
 
+       /* we don't want to overwrite the superblock on the drive,
+        * so we make sure to start at an offset of at least 1MB
+        */
+       search_start = max((u64)1024 * 1024, search_start);
        key.objectid = device->devid;
        key.offset = search_start;
        key.type = BTRFS_DEV_EXTENT_KEY;
@@ -285,6 +499,7 @@ int btrfs_add_device(struct btrfs_trans_handle *trans,
        leaf = path->nodes[0];
        dev_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_item);
 
+       device->devid = free_devid;
        btrfs_set_device_id(leaf, dev_item, device->devid);
        btrfs_set_device_type(leaf, dev_item, device->type);
        btrfs_set_device_io_align(leaf, dev_item, device->io_align);
@@ -382,7 +597,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        struct btrfs_device *device = NULL;
        struct btrfs_chunk *chunk;
        struct list_head private_devs;
-       struct list_head *dev_list = &extent_root->fs_info->devices;
+       struct list_head *dev_list = &extent_root->fs_info->fs_devices->devices;
        struct list_head *cur;
        struct extent_map_tree *em_tree;
        struct map_lookup *map;
@@ -449,7 +664,7 @@ again:
                                             key.objectid,
                                             calc_size, &dev_offset);
                BUG_ON(ret);
-
+printk("alloc chunk size %Lu from dev %Lu\n", calc_size, device->devid);
                device->bytes_used += calc_size;
                ret = btrfs_update_device(trans, device);
                BUG_ON(ret);
@@ -592,17 +807,9 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio)
 
 struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid)
 {
-       struct btrfs_device *dev;
-       struct list_head *cur = root->fs_info->devices.next;
-       struct list_head *head = &root->fs_info->devices;
+       struct list_head *head = &root->fs_info->fs_devices->devices;
 
-       while(cur != head) {
-               dev = list_entry(cur, struct btrfs_device, dev_list);
-               if (dev->devid == devid)
-                       return dev;
-               cur = cur->next;
-       }
-       return NULL;
+       return __find_device(head, devid);
 }
 
 static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
@@ -699,15 +906,16 @@ static int read_one_dev(struct btrfs_root *root,
        devid = btrfs_device_id(leaf, dev_item);
        device = btrfs_find_device(root, devid);
        if (!device) {
+               printk("warning devid %Lu not found already\n", devid);
                device = kmalloc(sizeof(*device), GFP_NOFS);
                if (!device)
                        return -ENOMEM;
-               list_add(&device->dev_list, &root->fs_info->devices);
+               list_add(&device->dev_list,
+                        &root->fs_info->fs_devices->devices);
        }
 
        fill_device_from_item(leaf, dev_item, device);
        device->dev_root = root->fs_info->dev_root;
-       device->bdev = root->fs_info->sb->s_bdev;
        ret = 0;
 #if 0
        ret = btrfs_open_device(device);
index 20259128152ee54e0d14d128de4e827bcb157126..12f297eb05597313c2f370cf502d75dffb693102 100644 (file)
@@ -24,6 +24,8 @@ struct btrfs_device {
 
        struct block_device *bdev;
 
+       char *name;
+
        /* the internal btrfs device id */
        u64 devid;
 
@@ -49,6 +51,20 @@ struct btrfs_device {
        u8 uuid[BTRFS_DEV_UUID_SIZE];
 };
 
+struct btrfs_fs_devices {
+       u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
+
+       /* the device with this id has the most recent coyp of the super */
+       u64 latest_devid;
+       u64 latest_trans;
+       u64 lowest_devid;
+       u64 num_devices;
+       struct block_device *latest_bdev;
+       struct block_device *lowest_bdev;
+       struct list_head devices;
+       struct list_head list;
+};
+
 int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
                           struct btrfs_device *device,
                           u64 owner, u64 num_bytes, u64 *start);
@@ -67,4 +83,13 @@ int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf);
 int btrfs_map_block(struct btrfs_mapping_tree *map_tree,
                    u64 logical, u64 *phys, u64 *length,
                    struct btrfs_device **dev);
+int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
+                      int flags, void *holder);
+int btrfs_scan_one_device(const char *path, int flags, void *holder,
+                         struct btrfs_fs_devices **fs_devices_ret);
+int btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
+int btrfs_add_device(struct btrfs_trans_handle *trans,
+                    struct btrfs_root *root,
+                    struct btrfs_device *device);
+int btrfs_cleanup_fs_uuids(void);
 #endif