diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-03-24 15:02:07 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:01 -0400 |
commit | 8a4b83cc8bd75fca29ac68615896d9e92820e7c2 (patch) | |
tree | b7f99cf53c322665b78cca10742cc734ad070729 | |
parent | 239b14b32dc39232ebf9cce29ff77c4c564355fd (diff) |
Btrfs: Add support for device scanning and detection ioctls
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/ctree.h | 21 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 24 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 4 | ||||
-rw-r--r-- | fs/btrfs/ioctl.h | 6 | ||||
-rw-r--r-- | fs/btrfs/super.c | 61 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 236 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 25 |
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; | |||
37 | extern struct kmem_cache *btrfs_bit_radix_cachep; | 37 | extern struct kmem_cache *btrfs_bit_radix_cachep; |
38 | extern struct kmem_cache *btrfs_path_cachep; | 38 | extern 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 | ||
442 | struct btrfs_device; | 443 | struct btrfs_device; |
444 | struct btrfs_fs_devices; | ||
443 | struct btrfs_fs_info { | 445 | struct 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); | |||
677 | BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32); | 679 | BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32); |
678 | BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64); | 680 | BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64); |
679 | 681 | ||
682 | BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64); | ||
683 | BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item, | ||
684 | total_bytes, 64); | ||
685 | BTRFS_SETGET_STACK_FUNCS(stack_device_bytes_used, struct btrfs_dev_item, | ||
686 | bytes_used, 64); | ||
687 | BTRFS_SETGET_STACK_FUNCS(stack_device_io_align, struct btrfs_dev_item, | ||
688 | io_align, 32); | ||
689 | BTRFS_SETGET_STACK_FUNCS(stack_device_io_width, struct btrfs_dev_item, | ||
690 | io_width, 32); | ||
691 | BTRFS_SETGET_STACK_FUNCS(stack_device_sector_size, struct btrfs_dev_item, | ||
692 | sector_size, 32); | ||
693 | BTRFS_SETGET_STACK_FUNCS(stack_device_id, struct btrfs_dev_item, devid, 64); | ||
694 | |||
680 | static inline char *btrfs_device_uuid(struct btrfs_dev_item *d) | 695 | static 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); |
1107 | BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block, | 1122 | BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block, |
1108 | root_dir_objectid, 64); | 1123 | root_dir_objectid, 64); |
1124 | BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block, | ||
1125 | num_devices, 64); | ||
1109 | 1126 | ||
1110 | static inline unsigned long btrfs_leaf_data(struct extent_buffer *l) | 1127 | static 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 |
658 | struct btrfs_root *open_ctree(struct super_block *sb) | 658 | struct 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: | |||
859 | fail_iput: | 864 | fail_iput: |
860 | iput(fs_info->btree_inode); | 865 | iput(fs_info->btree_inode); |
861 | fail: | 866 | fail: |
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) |
23 | struct btrfs_device; | 23 | struct btrfs_device; |
24 | struct btrfs_fs_devices; | ||
24 | 25 | ||
25 | struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, | 26 | struct 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); |
30 | int clean_tree_block(struct btrfs_trans_handle *trans, | 31 | int 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); |
32 | struct btrfs_root *open_ctree(struct super_block *sb); | 33 | struct btrfs_root *open_ctree(struct super_block *sb, |
34 | struct btrfs_fs_devices *fs_devices); | ||
33 | int close_ctree(struct btrfs_root *root); | 35 | int close_ctree(struct btrfs_root *root); |
34 | int write_ctree_super(struct btrfs_trans_handle *trans, | 36 | int 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 | |||
25 | struct btrfs_ioctl_vol_args { | 27 | struct 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 | ||
219 | static int btrfs_fill_super(struct super_block * sb, void * data, int silent) | 220 | static 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 | ||
335 | int btrfs_get_sb_bdev(struct file_system_type *fs_type, | 338 | int 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, | |||
408 | error_s: | 417 | error_s: |
409 | error = PTR_ERR(s); | 418 | error = PTR_ERR(s); |
410 | error_bdev: | 419 | error_bdev: |
411 | close_bdev_excl(bdev); | 420 | btrfs_close_devices(fs_devices); |
412 | error: | 421 | error: |
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 | ||
448 | static 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 | |||
455 | static struct file_system_type btrfs_fs_type = { | 456 | static 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 | ||
464 | static 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 | } | ||
484 | out: | ||
485 | kfree(vol); | ||
486 | return 0; | ||
487 | } | ||
488 | |||
463 | static void btrfs_write_super_lockfs(struct super_block *sb) | 489 | static 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 | ||
572 | module_init(init_btrfs_fs) | 599 | module_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 | }; |
32 | static DEFINE_MUTEX(uuid_mutex); | ||
33 | static LIST_HEAD(fs_uuids); | ||
34 | |||
35 | int 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 | |||
61 | static 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 | |||
74 | static 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 | |||
87 | static 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 | |||
139 | int 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 | |||
158 | int 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); | ||
171 | printk("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; | ||
181 | printk("lowest bdev %s\n", device->name); | ||
182 | } | ||
183 | device->bdev = bdev; | ||
184 | } | ||
185 | mutex_unlock(&uuid_mutex); | ||
186 | return 0; | ||
187 | fail: | ||
188 | mutex_unlock(&uuid_mutex); | ||
189 | btrfs_close_devices(fs_devices); | ||
190 | return ret; | ||
191 | } | ||
192 | |||
193 | int 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 | |||
232 | error_brelse: | ||
233 | brelse(bh); | ||
234 | error_close: | ||
235 | close_bdev_excl(bdev); | ||
236 | printk("scan one closes bdev %s\n", path); | ||
237 | error: | ||
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 | 667 | printk("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 | ||
593 | struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid) | 808 | struct 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 | ||
608 | static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, | 815 | 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, | |||
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 | ||
54 | struct 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 | |||
52 | int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, | 68 | int 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); | |||
67 | int btrfs_map_block(struct btrfs_mapping_tree *map_tree, | 83 | int 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); |
86 | int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, | ||
87 | int flags, void *holder); | ||
88 | int btrfs_scan_one_device(const char *path, int flags, void *holder, | ||
89 | struct btrfs_fs_devices **fs_devices_ret); | ||
90 | int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); | ||
91 | int btrfs_add_device(struct btrfs_trans_handle *trans, | ||
92 | struct btrfs_root *root, | ||
93 | struct btrfs_device *device); | ||
94 | int btrfs_cleanup_fs_uuids(void); | ||
70 | #endif | 95 | #endif |