aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-03-24 15:02:07 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:01 -0400
commit8a4b83cc8bd75fca29ac68615896d9e92820e7c2 (patch)
treeb7f99cf53c322665b78cca10742cc734ad070729 /fs/btrfs
parent239b14b32dc39232ebf9cce29ff77c4c564355fd (diff)
Btrfs: Add support for device scanning and detection ioctls
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h21
-rw-r--r--fs/btrfs/disk-io.c24
-rw-r--r--fs/btrfs/disk-io.h4
-rw-r--r--fs/btrfs/ioctl.h6
-rw-r--r--fs/btrfs/super.c61
-rw-r--r--fs/btrfs/volumes.c236
-rw-r--r--fs/btrfs/volumes.h25
7 files changed, 333 insertions, 44 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index acf22ad6115c..7556f8319c60 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -37,7 +37,7 @@ extern struct kmem_cache *btrfs_transaction_cachep;
37extern struct kmem_cache *btrfs_bit_radix_cachep; 37extern struct kmem_cache *btrfs_bit_radix_cachep;
38extern struct kmem_cache *btrfs_path_cachep; 38extern struct kmem_cache *btrfs_path_cachep;
39 39
40#define BTRFS_MAGIC "_B4RfS_M" 40#define BTRFS_MAGIC "_B5RfS_M"
41 41
42#define BTRFS_MAX_LEVEL 8 42#define BTRFS_MAX_LEVEL 8
43 43
@@ -238,6 +238,7 @@ struct btrfs_super_block {
238 __le64 total_bytes; 238 __le64 total_bytes;
239 __le64 bytes_used; 239 __le64 bytes_used;
240 __le64 root_dir_objectid; 240 __le64 root_dir_objectid;
241 __le64 num_devices;
241 __le32 sectorsize; 242 __le32 sectorsize;
242 __le32 nodesize; 243 __le32 nodesize;
243 __le32 leafsize; 244 __le32 leafsize;
@@ -440,6 +441,7 @@ struct btrfs_block_group_cache {
440}; 441};
441 442
442struct btrfs_device; 443struct btrfs_device;
444struct btrfs_fs_devices;
443struct btrfs_fs_info { 445struct btrfs_fs_info {
444 u8 fsid[BTRFS_FSID_SIZE]; 446 u8 fsid[BTRFS_FSID_SIZE];
445 struct btrfs_root *extent_root; 447 struct btrfs_root *extent_root;
@@ -489,7 +491,7 @@ struct btrfs_fs_info {
489 u64 total_pinned; 491 u64 total_pinned;
490 struct list_head dirty_cowonly_roots; 492 struct list_head dirty_cowonly_roots;
491 493
492 struct list_head devices; 494 struct btrfs_fs_devices *fs_devices;
493 struct list_head space_info; 495 struct list_head space_info;
494 spinlock_t delalloc_lock; 496 spinlock_t delalloc_lock;
495 spinlock_t new_trans_lock; 497 spinlock_t new_trans_lock;
@@ -677,6 +679,19 @@ BTRFS_SETGET_FUNCS(device_io_width, struct btrfs_dev_item, io_width, 32);
677BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32); 679BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32);
678BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64); 680BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64);
679 681
682BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64);
683BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item,
684 total_bytes, 64);
685BTRFS_SETGET_STACK_FUNCS(stack_device_bytes_used, struct btrfs_dev_item,
686 bytes_used, 64);
687BTRFS_SETGET_STACK_FUNCS(stack_device_io_align, struct btrfs_dev_item,
688 io_align, 32);
689BTRFS_SETGET_STACK_FUNCS(stack_device_io_width, struct btrfs_dev_item,
690 io_width, 32);
691BTRFS_SETGET_STACK_FUNCS(stack_device_sector_size, struct btrfs_dev_item,
692 sector_size, 32);
693BTRFS_SETGET_STACK_FUNCS(stack_device_id, struct btrfs_dev_item, devid, 64);
694
680static inline char *btrfs_device_uuid(struct btrfs_dev_item *d) 695static inline char *btrfs_device_uuid(struct btrfs_dev_item *d)
681{ 696{
682 return (char *)d + offsetof(struct btrfs_dev_item, uuid); 697 return (char *)d + offsetof(struct btrfs_dev_item, uuid);
@@ -1106,6 +1121,8 @@ BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block,
1106 stripesize, 32); 1121 stripesize, 32);
1107BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block, 1122BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block,
1108 root_dir_objectid, 64); 1123 root_dir_objectid, 64);
1124BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block,
1125 num_devices, 64);
1109 1126
1110static inline unsigned long btrfs_leaf_data(struct extent_buffer *l) 1127static inline unsigned long btrfs_leaf_data(struct extent_buffer *l)
1111{ 1128{
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 4890151cd68d..f971a29e4f20 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -365,12 +365,12 @@ static int close_all_devices(struct btrfs_fs_info *fs_info)
365 struct list_head *next; 365 struct list_head *next;
366 struct btrfs_device *device; 366 struct btrfs_device *device;
367 367
368 list = &fs_info->devices; 368 list = &fs_info->fs_devices->devices;
369 while(!list_empty(list)) { 369 list_for_each(next, list) {
370 next = list->next;
371 list_del(next);
372 device = list_entry(next, struct btrfs_device, dev_list); 370 device = list_entry(next, struct btrfs_device, dev_list);
373 kfree(device); 371 if (device->bdev && device->bdev != fs_info->sb->s_bdev)
372 close_bdev_excl(device->bdev);
373 device->bdev = NULL;
374 } 374 }
375 return 0; 375 return 0;
376} 376}
@@ -655,7 +655,8 @@ static int add_hasher(struct btrfs_fs_info *info, char *type) {
655 return 0; 655 return 0;
656} 656}
657#endif 657#endif
658struct btrfs_root *open_ctree(struct super_block *sb) 658struct btrfs_root *open_ctree(struct super_block *sb,
659 struct btrfs_fs_devices *fs_devices)
659{ 660{
660 u32 sectorsize; 661 u32 sectorsize;
661 u32 nodesize; 662 u32 nodesize;
@@ -697,8 +698,8 @@ struct btrfs_root *open_ctree(struct super_block *sb)
697 fs_info->extent_root = extent_root; 698 fs_info->extent_root = extent_root;
698 fs_info->chunk_root = chunk_root; 699 fs_info->chunk_root = chunk_root;
699 fs_info->dev_root = dev_root; 700 fs_info->dev_root = dev_root;
701 fs_info->fs_devices = fs_devices;
700 INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); 702 INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
701 INIT_LIST_HEAD(&fs_info->devices);
702 INIT_LIST_HEAD(&fs_info->space_info); 703 INIT_LIST_HEAD(&fs_info->space_info);
703 btrfs_mapping_init(&fs_info->mapping_tree); 704 btrfs_mapping_init(&fs_info->mapping_tree);
704 fs_info->sb = sb; 705 fs_info->sb = sb;
@@ -779,6 +780,12 @@ struct btrfs_root *open_ctree(struct super_block *sb)
779 if (!btrfs_super_root(disk_super)) 780 if (!btrfs_super_root(disk_super))
780 goto fail_sb_buffer; 781 goto fail_sb_buffer;
781 782
783 if (btrfs_super_num_devices(disk_super) != fs_devices->num_devices) {
784 printk("Btrfs: wanted %llu devices, but found %llu\n",
785 (unsigned long long)btrfs_super_num_devices(disk_super),
786 (unsigned long long)fs_devices->num_devices);
787 goto fail_sb_buffer;
788 }
782 nodesize = btrfs_super_nodesize(disk_super); 789 nodesize = btrfs_super_nodesize(disk_super);
783 leafsize = btrfs_super_leafsize(disk_super); 790 leafsize = btrfs_super_leafsize(disk_super);
784 sectorsize = btrfs_super_sectorsize(disk_super); 791 sectorsize = btrfs_super_sectorsize(disk_super);
@@ -799,8 +806,6 @@ struct btrfs_root *open_ctree(struct super_block *sb)
799 } 806 }
800 807
801 mutex_lock(&fs_info->fs_mutex); 808 mutex_lock(&fs_info->fs_mutex);
802 ret = btrfs_read_super_device(tree_root, fs_info->sb_buffer);
803 BUG_ON(ret);
804 809
805 ret = btrfs_read_sys_array(tree_root); 810 ret = btrfs_read_sys_array(tree_root);
806 BUG_ON(ret); 811 BUG_ON(ret);
@@ -859,6 +864,7 @@ fail_sb_buffer:
859fail_iput: 864fail_iput:
860 iput(fs_info->btree_inode); 865 iput(fs_info->btree_inode);
861fail: 866fail:
867 close_all_devices(fs_info);
862 kfree(extent_root); 868 kfree(extent_root);
863 kfree(tree_root); 869 kfree(tree_root);
864 kfree(fs_info); 870 kfree(fs_info);
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index 206cb48638f7..b7cbc58a5553 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -21,6 +21,7 @@
21 21
22#define BTRFS_SUPER_INFO_OFFSET (16 * 1024) 22#define BTRFS_SUPER_INFO_OFFSET (16 * 1024)
23struct btrfs_device; 23struct btrfs_device;
24struct btrfs_fs_devices;
24 25
25struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, 26struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
26 u32 blocksize); 27 u32 blocksize);
@@ -29,7 +30,8 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
29 u64 bytenr, u32 blocksize); 30 u64 bytenr, u32 blocksize);
30int clean_tree_block(struct btrfs_trans_handle *trans, 31int clean_tree_block(struct btrfs_trans_handle *trans,
31 struct btrfs_root *root, struct extent_buffer *buf); 32 struct btrfs_root *root, struct extent_buffer *buf);
32struct btrfs_root *open_ctree(struct super_block *sb); 33struct btrfs_root *open_ctree(struct super_block *sb,
34 struct btrfs_fs_devices *fs_devices);
33int close_ctree(struct btrfs_root *root); 35int close_ctree(struct btrfs_root *root);
34int write_ctree_super(struct btrfs_trans_handle *trans, 36int write_ctree_super(struct btrfs_trans_handle *trans,
35 struct btrfs_root *root); 37 struct btrfs_root *root);
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index 8c6290665d49..4551e82013c8 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -22,8 +22,10 @@
22 22
23#define BTRFS_IOCTL_MAGIC 0x94 23#define BTRFS_IOCTL_MAGIC 0x94
24#define BTRFS_VOL_NAME_MAX 255 24#define BTRFS_VOL_NAME_MAX 255
25#define BTRFS_PATH_NAME_MAX 4095
26
25struct btrfs_ioctl_vol_args { 27struct btrfs_ioctl_vol_args {
26 char name[BTRFS_VOL_NAME_MAX + 1]; 28 char name[BTRFS_PATH_NAME_MAX + 1];
27}; 29};
28 30
29#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ 31#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
@@ -32,4 +34,6 @@ struct btrfs_ioctl_vol_args {
32 struct btrfs_ioctl_vol_args) 34 struct btrfs_ioctl_vol_args)
33#define BTRFS_IOC_RESIZE _IOW(BTRFS_IOCTL_MAGIC, 3, \ 35#define BTRFS_IOC_RESIZE _IOW(BTRFS_IOCTL_MAGIC, 3, \
34 struct btrfs_ioctl_vol_args) 36 struct btrfs_ioctl_vol_args)
37#define BTRFS_IOC_SCAN_DEV _IOW(BTRFS_IOCTL_MAGIC, 4, \
38 struct btrfs_ioctl_vol_args)
35#endif 39#endif
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 67ed216df475..9624923a33dc 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -44,6 +44,7 @@
44#include "ioctl.h" 44#include "ioctl.h"
45#include "print-tree.h" 45#include "print-tree.h"
46#include "xattr.h" 46#include "xattr.h"
47#include "volumes.h"
47 48
48#define BTRFS_SUPER_MAGIC 0x9123683E 49#define BTRFS_SUPER_MAGIC 0x9123683E
49 50
@@ -216,7 +217,9 @@ static int parse_options (char * options,
216 return 1; 217 return 1;
217} 218}
218 219
219static int btrfs_fill_super(struct super_block * sb, void * data, int silent) 220static int btrfs_fill_super(struct super_block * sb,
221 struct btrfs_fs_devices *fs_devices,
222 void * data, int silent)
220{ 223{
221 struct inode * inode; 224 struct inode * inode;
222 struct dentry * root_dentry; 225 struct dentry * root_dentry;
@@ -231,7 +234,7 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
231 sb->s_xattr = btrfs_xattr_handlers; 234 sb->s_xattr = btrfs_xattr_handlers;
232 sb->s_time_gran = 1; 235 sb->s_time_gran = 1;
233 236
234 tree_root = open_ctree(sb); 237 tree_root = open_ctree(sb, fs_devices);
235 238
236 if (!tree_root || IS_ERR(tree_root)) { 239 if (!tree_root || IS_ERR(tree_root)) {
237 printk("btrfs: open_ctree failed\n"); 240 printk("btrfs: open_ctree failed\n");
@@ -334,18 +337,23 @@ static int test_bdev_super(struct super_block *s, void *data)
334 337
335int btrfs_get_sb_bdev(struct file_system_type *fs_type, 338int btrfs_get_sb_bdev(struct file_system_type *fs_type,
336 int flags, const char *dev_name, void *data, 339 int flags, const char *dev_name, void *data,
337 int (*fill_super)(struct super_block *, void *, int),
338 struct vfsmount *mnt, const char *subvol) 340 struct vfsmount *mnt, const char *subvol)
339{ 341{
340 struct block_device *bdev = NULL; 342 struct block_device *bdev = NULL;
341 struct super_block *s; 343 struct super_block *s;
342 struct dentry *root; 344 struct dentry *root;
345 struct btrfs_fs_devices *fs_devices = NULL;
343 int error = 0; 346 int error = 0;
344 347
345 bdev = open_bdev_excl(dev_name, flags, fs_type); 348 error = btrfs_scan_one_device(dev_name, flags, fs_type, &fs_devices);
346 if (IS_ERR(bdev)) 349 if (error)
347 return PTR_ERR(bdev); 350 return error;
348 351
352 error = btrfs_open_devices(fs_devices, flags, fs_type);
353 if (error)
354 return error;
355
356 bdev = fs_devices->lowest_bdev;
349 /* 357 /*
350 * once the super is inserted into the list by sget, s_umount 358 * once the super is inserted into the list by sget, s_umount
351 * will protect the lockfs code from trying to start a snapshot 359 * 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,
372 s->s_flags = flags; 380 s->s_flags = flags;
373 strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id)); 381 strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
374 sb_set_blocksize(s, block_size(bdev)); 382 sb_set_blocksize(s, block_size(bdev));
375 error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); 383 error = btrfs_fill_super(s, fs_devices, data,
384 flags & MS_SILENT ? 1 : 0);
376 if (error) { 385 if (error) {
377 up_write(&s->s_umount); 386 up_write(&s->s_umount);
378 deactivate_super(s); 387 deactivate_super(s);
@@ -408,7 +417,7 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type,
408error_s: 417error_s:
409 error = PTR_ERR(s); 418 error = PTR_ERR(s);
410error_bdev: 419error_bdev:
411 close_bdev_excl(bdev); 420 btrfs_close_devices(fs_devices);
412error: 421error:
413 return error; 422 return error;
414} 423}
@@ -421,8 +430,7 @@ static int btrfs_get_sb(struct file_system_type *fs_type,
421 char *subvol_name = NULL; 430 char *subvol_name = NULL;
422 431
423 parse_options((char *)data, NULL, &subvol_name); 432 parse_options((char *)data, NULL, &subvol_name);
424 ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data, 433 ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data, mnt,
425 btrfs_fill_super, mnt,
426 subvol_name ? subvol_name : "default"); 434 subvol_name ? subvol_name : "default");
427 if (subvol_name) 435 if (subvol_name)
428 kfree(subvol_name); 436 kfree(subvol_name);
@@ -445,13 +453,6 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
445 return 0; 453 return 0;
446} 454}
447 455
448static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
449 unsigned long arg)
450{
451 printk("btrfs control ioctl %d\n", cmd);
452 return 0;
453}
454
455static struct file_system_type btrfs_fs_type = { 456static struct file_system_type btrfs_fs_type = {
456 .owner = THIS_MODULE, 457 .owner = THIS_MODULE,
457 .name = "btrfs", 458 .name = "btrfs",
@@ -460,6 +461,31 @@ static struct file_system_type btrfs_fs_type = {
460 .fs_flags = FS_REQUIRES_DEV, 461 .fs_flags = FS_REQUIRES_DEV,
461}; 462};
462 463
464static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
465 unsigned long arg)
466{
467 struct btrfs_ioctl_vol_args *vol;
468 struct btrfs_fs_devices *fs_devices;
469 int ret;
470 int len;
471
472 vol = kmalloc(sizeof(*vol), GFP_KERNEL);
473 if (copy_from_user(vol, (void __user *)arg, sizeof(*vol))) {
474 ret = -EFAULT;
475 goto out;
476 }
477 len = strnlen(vol->name, BTRFS_PATH_NAME_MAX);
478 switch (cmd) {
479 case BTRFS_IOC_SCAN_DEV:
480 ret = btrfs_scan_one_device(vol->name, MS_RDONLY,
481 &btrfs_fs_type, &fs_devices);
482 break;
483 }
484out:
485 kfree(vol);
486 return 0;
487}
488
463static void btrfs_write_super_lockfs(struct super_block *sb) 489static void btrfs_write_super_lockfs(struct super_block *sb)
464{ 490{
465 struct btrfs_root *root = btrfs_sb(sb); 491 struct btrfs_root *root = btrfs_sb(sb);
@@ -567,6 +593,7 @@ static void __exit exit_btrfs_fs(void)
567 btrfs_interface_exit(); 593 btrfs_interface_exit();
568 unregister_filesystem(&btrfs_fs_type); 594 unregister_filesystem(&btrfs_fs_type);
569 btrfs_exit_sysfs(); 595 btrfs_exit_sysfs();
596 btrfs_cleanup_fs_uuids();
570} 597}
571 598
572module_init(init_btrfs_fs) 599module_init(init_btrfs_fs)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 16fb6bbe6e28..263f01cc3db4 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -17,6 +17,7 @@
17 */ 17 */
18#include <linux/sched.h> 18#include <linux/sched.h>
19#include <linux/bio.h> 19#include <linux/bio.h>
20#include <linux/buffer_head.h>
20#include "ctree.h" 21#include "ctree.h"
21#include "extent_map.h" 22#include "extent_map.h"
22#include "disk-io.h" 23#include "disk-io.h"
@@ -28,6 +29,215 @@ struct map_lookup {
28 struct btrfs_device *dev; 29 struct btrfs_device *dev;
29 u64 physical; 30 u64 physical;
30}; 31};
32static DEFINE_MUTEX(uuid_mutex);
33static LIST_HEAD(fs_uuids);
34
35int btrfs_cleanup_fs_uuids(void)
36{
37 struct btrfs_fs_devices *fs_devices;
38 struct list_head *uuid_cur;
39 struct list_head *devices_cur;
40 struct btrfs_device *dev;
41
42 list_for_each(uuid_cur, &fs_uuids) {
43 fs_devices = list_entry(uuid_cur, struct btrfs_fs_devices,
44 list);
45 while(!list_empty(&fs_devices->devices)) {
46 devices_cur = fs_devices->devices.next;
47 dev = list_entry(devices_cur, struct btrfs_device,
48 dev_list);
49 printk("uuid cleanup finds %s\n", dev->name);
50 if (dev->bdev) {
51 printk("closing\n");
52 close_bdev_excl(dev->bdev);
53 }
54 list_del(&dev->dev_list);
55 kfree(dev);
56 }
57 }
58 return 0;
59}
60
61static struct btrfs_device *__find_device(struct list_head *head, u64 devid)
62{
63 struct btrfs_device *dev;
64 struct list_head *cur;
65
66 list_for_each(cur, head) {
67 dev = list_entry(cur, struct btrfs_device, dev_list);
68 if (dev->devid == devid)
69 return dev;
70 }
71 return NULL;
72}
73
74static struct btrfs_fs_devices *find_fsid(u8 *fsid)
75{
76 struct list_head *cur;
77 struct btrfs_fs_devices *fs_devices;
78
79 list_for_each(cur, &fs_uuids) {
80 fs_devices = list_entry(cur, struct btrfs_fs_devices, list);
81 if (memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE) == 0)
82 return fs_devices;
83 }
84 return NULL;
85}
86
87static int device_list_add(const char *path,
88 struct btrfs_super_block *disk_super,
89 u64 devid, struct btrfs_fs_devices **fs_devices_ret)
90{
91 struct btrfs_device *device;
92 struct btrfs_fs_devices *fs_devices;
93 u64 found_transid = btrfs_super_generation(disk_super);
94
95 fs_devices = find_fsid(disk_super->fsid);
96 if (!fs_devices) {
97 fs_devices = kmalloc(sizeof(*fs_devices), GFP_NOFS);
98 if (!fs_devices)
99 return -ENOMEM;
100 INIT_LIST_HEAD(&fs_devices->devices);
101 list_add(&fs_devices->list, &fs_uuids);
102 memcpy(fs_devices->fsid, disk_super->fsid, BTRFS_FSID_SIZE);
103 fs_devices->latest_devid = devid;
104 fs_devices->latest_trans = found_transid;
105 fs_devices->lowest_devid = (u64)-1;
106 fs_devices->num_devices = 0;
107 device = NULL;
108 } else {
109 device = __find_device(&fs_devices->devices, devid);
110 }
111 if (!device) {
112 device = kzalloc(sizeof(*device), GFP_NOFS);
113 if (!device) {
114 /* we can safely leave the fs_devices entry around */
115 return -ENOMEM;
116 }
117 device->devid = devid;
118 device->name = kstrdup(path, GFP_NOFS);
119 if (!device->name) {
120 kfree(device);
121 return -ENOMEM;
122 }
123 list_add(&device->dev_list, &fs_devices->devices);
124 fs_devices->num_devices++;
125 }
126
127 if (found_transid > fs_devices->latest_trans) {
128 fs_devices->latest_devid = devid;
129 fs_devices->latest_trans = found_transid;
130 }
131 if (fs_devices->lowest_devid > devid) {
132 fs_devices->lowest_devid = devid;
133 printk("lowest devid now %Lu\n", devid);
134 }
135 *fs_devices_ret = fs_devices;
136 return 0;
137}
138
139int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
140{
141 struct list_head *head = &fs_devices->devices;
142 struct list_head *cur;
143 struct btrfs_device *device;
144
145 mutex_lock(&uuid_mutex);
146 list_for_each(cur, head) {
147 device = list_entry(cur, struct btrfs_device, dev_list);
148 if (device->bdev) {
149 close_bdev_excl(device->bdev);
150 printk("close devices closes %s\n", device->name);
151 }
152 device->bdev = NULL;
153 }
154 mutex_unlock(&uuid_mutex);
155 return 0;
156}
157
158int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
159 int flags, void *holder)
160{
161 struct block_device *bdev;
162 struct list_head *head = &fs_devices->devices;
163 struct list_head *cur;
164 struct btrfs_device *device;
165 int ret;
166
167 mutex_lock(&uuid_mutex);
168 list_for_each(cur, head) {
169 device = list_entry(cur, struct btrfs_device, dev_list);
170 bdev = open_bdev_excl(device->name, flags, holder);
171printk("opening %s devid %Lu\n", device->name, device->devid);
172 if (IS_ERR(bdev)) {
173 printk("open %s failed\n", device->name);
174 ret = PTR_ERR(bdev);
175 goto fail;
176 }
177 if (device->devid == fs_devices->latest_devid)
178 fs_devices->latest_bdev = bdev;
179 if (device->devid == fs_devices->lowest_devid) {
180 fs_devices->lowest_bdev = bdev;
181printk("lowest bdev %s\n", device->name);
182 }
183 device->bdev = bdev;
184 }
185 mutex_unlock(&uuid_mutex);
186 return 0;
187fail:
188 mutex_unlock(&uuid_mutex);
189 btrfs_close_devices(fs_devices);
190 return ret;
191}
192
193int btrfs_scan_one_device(const char *path, int flags, void *holder,
194 struct btrfs_fs_devices **fs_devices_ret)
195{
196 struct btrfs_super_block *disk_super;
197 struct block_device *bdev;
198 struct buffer_head *bh;
199 int ret;
200 u64 devid;
201
202 mutex_lock(&uuid_mutex);
203
204 printk("scan one opens %s\n", path);
205 bdev = open_bdev_excl(path, flags, holder);
206
207 if (IS_ERR(bdev)) {
208 printk("open failed\n");
209 ret = PTR_ERR(bdev);
210 goto error;
211 }
212
213 ret = set_blocksize(bdev, 4096);
214 if (ret)
215 goto error_close;
216 bh = __bread(bdev, BTRFS_SUPER_INFO_OFFSET / 4096, 4096);
217 if (!bh) {
218 ret = -EIO;
219 goto error_close;
220 }
221 disk_super = (struct btrfs_super_block *)bh->b_data;
222 if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC,
223 sizeof(disk_super->magic))) {
224 printk("no btrfs found on %s\n", path);
225 ret = -ENOENT;
226 goto error_brelse;
227 }
228 devid = le64_to_cpu(disk_super->dev_item.devid);
229 printk("found device %Lu on %s\n", devid, path);
230 ret = device_list_add(path, disk_super, devid, fs_devices_ret);
231
232error_brelse:
233 brelse(bh);
234error_close:
235 close_bdev_excl(bdev);
236 printk("scan one closes bdev %s\n", path);
237error:
238 mutex_unlock(&uuid_mutex);
239 return ret;
240}
31 241
32/* 242/*
33 * this uses a pretty simple search, the expectation is that it is 243 * 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,
56 266
57 /* FIXME use last free of some kind */ 267 /* FIXME use last free of some kind */
58 268
269 /* we don't want to overwrite the superblock on the drive,
270 * so we make sure to start at an offset of at least 1MB
271 */
272 search_start = max((u64)1024 * 1024, search_start);
59 key.objectid = device->devid; 273 key.objectid = device->devid;
60 key.offset = search_start; 274 key.offset = search_start;
61 key.type = BTRFS_DEV_EXTENT_KEY; 275 key.type = BTRFS_DEV_EXTENT_KEY;
@@ -285,6 +499,7 @@ int btrfs_add_device(struct btrfs_trans_handle *trans,
285 leaf = path->nodes[0]; 499 leaf = path->nodes[0];
286 dev_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_item); 500 dev_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_item);
287 501
502 device->devid = free_devid;
288 btrfs_set_device_id(leaf, dev_item, device->devid); 503 btrfs_set_device_id(leaf, dev_item, device->devid);
289 btrfs_set_device_type(leaf, dev_item, device->type); 504 btrfs_set_device_type(leaf, dev_item, device->type);
290 btrfs_set_device_io_align(leaf, dev_item, device->io_align); 505 btrfs_set_device_io_align(leaf, dev_item, device->io_align);
@@ -382,7 +597,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
382 struct btrfs_device *device = NULL; 597 struct btrfs_device *device = NULL;
383 struct btrfs_chunk *chunk; 598 struct btrfs_chunk *chunk;
384 struct list_head private_devs; 599 struct list_head private_devs;
385 struct list_head *dev_list = &extent_root->fs_info->devices; 600 struct list_head *dev_list = &extent_root->fs_info->fs_devices->devices;
386 struct list_head *cur; 601 struct list_head *cur;
387 struct extent_map_tree *em_tree; 602 struct extent_map_tree *em_tree;
388 struct map_lookup *map; 603 struct map_lookup *map;
@@ -449,7 +664,7 @@ again:
449 key.objectid, 664 key.objectid,
450 calc_size, &dev_offset); 665 calc_size, &dev_offset);
451 BUG_ON(ret); 666 BUG_ON(ret);
452 667printk("alloc chunk size %Lu from dev %Lu\n", calc_size, device->devid);
453 device->bytes_used += calc_size; 668 device->bytes_used += calc_size;
454 ret = btrfs_update_device(trans, device); 669 ret = btrfs_update_device(trans, device);
455 BUG_ON(ret); 670 BUG_ON(ret);
@@ -592,17 +807,9 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio)
592 807
593struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid) 808struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid)
594{ 809{
595 struct btrfs_device *dev; 810 struct list_head *head = &root->fs_info->fs_devices->devices;
596 struct list_head *cur = root->fs_info->devices.next;
597 struct list_head *head = &root->fs_info->devices;
598 811
599 while(cur != head) { 812 return __find_device(head, devid);
600 dev = list_entry(cur, struct btrfs_device, dev_list);
601 if (dev->devid == devid)
602 return dev;
603 cur = cur->next;
604 }
605 return NULL;
606} 813}
607 814
608static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, 815static 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,
699 devid = btrfs_device_id(leaf, dev_item); 906 devid = btrfs_device_id(leaf, dev_item);
700 device = btrfs_find_device(root, devid); 907 device = btrfs_find_device(root, devid);
701 if (!device) { 908 if (!device) {
909 printk("warning devid %Lu not found already\n", devid);
702 device = kmalloc(sizeof(*device), GFP_NOFS); 910 device = kmalloc(sizeof(*device), GFP_NOFS);
703 if (!device) 911 if (!device)
704 return -ENOMEM; 912 return -ENOMEM;
705 list_add(&device->dev_list, &root->fs_info->devices); 913 list_add(&device->dev_list,
914 &root->fs_info->fs_devices->devices);
706 } 915 }
707 916
708 fill_device_from_item(leaf, dev_item, device); 917 fill_device_from_item(leaf, dev_item, device);
709 device->dev_root = root->fs_info->dev_root; 918 device->dev_root = root->fs_info->dev_root;
710 device->bdev = root->fs_info->sb->s_bdev;
711 ret = 0; 919 ret = 0;
712#if 0 920#if 0
713 ret = btrfs_open_device(device); 921 ret = btrfs_open_device(device);
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 20259128152e..12f297eb0559 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -24,6 +24,8 @@ struct btrfs_device {
24 24
25 struct block_device *bdev; 25 struct block_device *bdev;
26 26
27 char *name;
28
27 /* the internal btrfs device id */ 29 /* the internal btrfs device id */
28 u64 devid; 30 u64 devid;
29 31
@@ -49,6 +51,20 @@ struct btrfs_device {
49 u8 uuid[BTRFS_DEV_UUID_SIZE]; 51 u8 uuid[BTRFS_DEV_UUID_SIZE];
50}; 52};
51 53
54struct btrfs_fs_devices {
55 u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
56
57 /* the device with this id has the most recent coyp of the super */
58 u64 latest_devid;
59 u64 latest_trans;
60 u64 lowest_devid;
61 u64 num_devices;
62 struct block_device *latest_bdev;
63 struct block_device *lowest_bdev;
64 struct list_head devices;
65 struct list_head list;
66};
67
52int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, 68int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
53 struct btrfs_device *device, 69 struct btrfs_device *device,
54 u64 owner, u64 num_bytes, u64 *start); 70 u64 owner, u64 num_bytes, u64 *start);
@@ -67,4 +83,13 @@ int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf);
67int btrfs_map_block(struct btrfs_mapping_tree *map_tree, 83int btrfs_map_block(struct btrfs_mapping_tree *map_tree,
68 u64 logical, u64 *phys, u64 *length, 84 u64 logical, u64 *phys, u64 *length,
69 struct btrfs_device **dev); 85 struct btrfs_device **dev);
86int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
87 int flags, void *holder);
88int btrfs_scan_one_device(const char *path, int flags, void *holder,
89 struct btrfs_fs_devices **fs_devices_ret);
90int btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
91int btrfs_add_device(struct btrfs_trans_handle *trans,
92 struct btrfs_root *root,
93 struct btrfs_device *device);
94int btrfs_cleanup_fs_uuids(void);
70#endif 95#endif