aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-05-07 11:43:44 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:02 -0400
commita061fc8da7b990faa41ca503e66faef3ecdeead0 (patch)
tree0d3b5b6e4d2164d507d9a16d5b38d373592a5c8f /fs/btrfs/volumes.c
parent5d9cd9ecbf40b8bd5045a3c2f1feb35db6a12266 (diff)
Btrfs: Add support for online device removal
This required a few structural changes to the code that manages bdev pointers: The VFS super block now gets an anon-bdev instead of a pointer to the lowest bdev. This allows us to avoid swapping the super block bdev pointer around at run time. The code to read in the super block no longer goes through the extent buffer interface. Things got ugly keeping the mapping constant. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c221
1 files changed, 212 insertions, 9 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index b38187573108..55da5f0c56e3 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -45,6 +45,16 @@ struct map_lookup {
45static DEFINE_MUTEX(uuid_mutex); 45static DEFINE_MUTEX(uuid_mutex);
46static LIST_HEAD(fs_uuids); 46static LIST_HEAD(fs_uuids);
47 47
48void btrfs_lock_volumes(void)
49{
50 mutex_lock(&uuid_mutex);
51}
52
53void btrfs_unlock_volumes(void)
54{
55 mutex_unlock(&uuid_mutex);
56}
57
48int btrfs_cleanup_fs_uuids(void) 58int btrfs_cleanup_fs_uuids(void)
49{ 59{
50 struct btrfs_fs_devices *fs_devices; 60 struct btrfs_fs_devices *fs_devices;
@@ -193,12 +203,14 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
193 ret = PTR_ERR(bdev); 203 ret = PTR_ERR(bdev);
194 goto fail; 204 goto fail;
195 } 205 }
206 set_blocksize(bdev, 4096);
196 if (device->devid == fs_devices->latest_devid) 207 if (device->devid == fs_devices->latest_devid)
197 fs_devices->latest_bdev = bdev; 208 fs_devices->latest_bdev = bdev;
198 if (device->devid == fs_devices->lowest_devid) { 209 if (device->devid == fs_devices->lowest_devid) {
199 fs_devices->lowest_bdev = bdev; 210 fs_devices->lowest_bdev = bdev;
200 } 211 }
201 device->bdev = bdev; 212 device->bdev = bdev;
213
202 } 214 }
203 mutex_unlock(&uuid_mutex); 215 mutex_unlock(&uuid_mutex);
204 return 0; 216 return 0;
@@ -393,6 +405,9 @@ int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
393 struct btrfs_path *path; 405 struct btrfs_path *path;
394 struct btrfs_root *root = device->dev_root; 406 struct btrfs_root *root = device->dev_root;
395 struct btrfs_key key; 407 struct btrfs_key key;
408 struct btrfs_key found_key;
409 struct extent_buffer *leaf = NULL;
410 struct btrfs_dev_extent *extent = NULL;
396 411
397 path = btrfs_alloc_path(); 412 path = btrfs_alloc_path();
398 if (!path) 413 if (!path)
@@ -403,8 +418,25 @@ int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
403 key.type = BTRFS_DEV_EXTENT_KEY; 418 key.type = BTRFS_DEV_EXTENT_KEY;
404 419
405 ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 420 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
421 if (ret > 0) {
422 ret = btrfs_previous_item(root, path, key.objectid,
423 BTRFS_DEV_EXTENT_KEY);
424 BUG_ON(ret);
425 leaf = path->nodes[0];
426 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
427 extent = btrfs_item_ptr(leaf, path->slots[0],
428 struct btrfs_dev_extent);
429 BUG_ON(found_key.offset > start || found_key.offset +
430 btrfs_dev_extent_length(leaf, extent) < start);
431 ret = 0;
432 } else if (ret == 0) {
433 leaf = path->nodes[0];
434 extent = btrfs_item_ptr(leaf, path->slots[0],
435 struct btrfs_dev_extent);
436 }
406 BUG_ON(ret); 437 BUG_ON(ret);
407 438
439 device->bytes_used -= btrfs_dev_extent_length(leaf, extent);
408 ret = btrfs_del_item(trans, root, path); 440 ret = btrfs_del_item(trans, root, path);
409 BUG_ON(ret); 441 BUG_ON(ret);
410 442
@@ -593,6 +625,170 @@ out:
593 return ret; 625 return ret;
594} 626}
595 627
628static int btrfs_rm_dev_item(struct btrfs_root *root,
629 struct btrfs_device *device)
630{
631 int ret;
632 struct btrfs_path *path;
633 struct block_device *bdev = device->bdev;
634 struct btrfs_device *next_dev;
635 struct btrfs_key key;
636 u64 total_bytes;
637 struct btrfs_fs_devices *fs_devices;
638 struct btrfs_trans_handle *trans;
639
640 root = root->fs_info->chunk_root;
641
642 path = btrfs_alloc_path();
643 if (!path)
644 return -ENOMEM;
645
646 trans = btrfs_start_transaction(root, 1);
647 key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
648 key.type = BTRFS_DEV_ITEM_KEY;
649 key.offset = device->devid;
650
651 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
652 if (ret < 0)
653 goto out;
654
655 if (ret > 0) {
656 ret = -ENOENT;
657 goto out;
658 }
659
660 ret = btrfs_del_item(trans, root, path);
661 if (ret)
662 goto out;
663
664 /*
665 * at this point, the device is zero sized. We want to
666 * remove it from the devices list and zero out the old super
667 */
668 list_del_init(&device->dev_list);
669 list_del_init(&device->dev_alloc_list);
670 fs_devices = root->fs_info->fs_devices;
671
672 next_dev = list_entry(fs_devices->devices.next, struct btrfs_device,
673 dev_list);
674 if (bdev == fs_devices->lowest_bdev)
675 fs_devices->lowest_bdev = next_dev->bdev;
676 if (bdev == root->fs_info->sb->s_bdev)
677 root->fs_info->sb->s_bdev = next_dev->bdev;
678 if (bdev == fs_devices->latest_bdev)
679 fs_devices->latest_bdev = next_dev->bdev;
680
681 total_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
682 btrfs_set_super_total_bytes(&root->fs_info->super_copy,
683 total_bytes - device->total_bytes);
684
685 total_bytes = btrfs_super_num_devices(&root->fs_info->super_copy);
686 btrfs_set_super_num_devices(&root->fs_info->super_copy,
687 total_bytes - 1);
688out:
689 btrfs_free_path(path);
690 btrfs_commit_transaction(trans, root);
691 return ret;
692}
693
694int btrfs_rm_device(struct btrfs_root *root, char *device_path)
695{
696 struct btrfs_device *device;
697 struct block_device *bdev;
698 struct buffer_head *bh;
699 struct btrfs_super_block *disk_super;
700 u64 all_avail;
701 u64 devid;
702 int ret = 0;
703
704 mutex_lock(&root->fs_info->fs_mutex);
705 mutex_lock(&uuid_mutex);
706
707 all_avail = root->fs_info->avail_data_alloc_bits |
708 root->fs_info->avail_system_alloc_bits |
709 root->fs_info->avail_metadata_alloc_bits;
710
711 if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) &&
712 root->fs_info->fs_devices->num_devices <= 4) {
713 printk("btrfs: unable to go below four devices on raid10\n");
714 ret = -EINVAL;
715 goto out;
716 }
717
718 if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) &&
719 root->fs_info->fs_devices->num_devices <= 2) {
720 printk("btrfs: unable to go below two devices on raid1\n");
721 ret = -EINVAL;
722 goto out;
723 }
724
725 bdev = open_bdev_excl(device_path, 0, root->fs_info->bdev_holder);
726 if (IS_ERR(bdev)) {
727 ret = PTR_ERR(bdev);
728 goto out;
729 }
730
731 bh = __bread(bdev, BTRFS_SUPER_INFO_OFFSET / 4096, 4096);
732 if (!bh) {
733 ret = -EIO;
734 goto error_close;
735 }
736 disk_super = (struct btrfs_super_block *)bh->b_data;
737 if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC,
738 sizeof(disk_super->magic))) {
739 ret = -ENOENT;
740 goto error_brelse;
741 }
742 if (memcmp(disk_super->fsid, root->fs_info->fsid, BTRFS_FSID_SIZE)) {
743 ret = -ENOENT;
744 goto error_brelse;
745 }
746 devid = le64_to_cpu(disk_super->dev_item.devid);
747 device = btrfs_find_device(root, devid, NULL);
748 if (!device) {
749 ret = -ENOENT;
750 goto error_brelse;
751 }
752
753 root->fs_info->fs_devices->num_devices--;
754
755 ret = btrfs_shrink_device(device, 0);
756 if (ret)
757 goto error_brelse;
758
759
760 ret = btrfs_rm_dev_item(root->fs_info->chunk_root, device);
761 if (ret)
762 goto error_brelse;
763
764 /* make sure this device isn't detected as part of the FS anymore */
765 memset(&disk_super->magic, 0, sizeof(disk_super->magic));
766 set_buffer_dirty(bh);
767 sync_dirty_buffer(bh);
768
769 brelse(bh);
770
771 /* one close for the device struct or super_block */
772 close_bdev_excl(device->bdev);
773
774 /* one close for us */
775 close_bdev_excl(device->bdev);
776
777 kfree(device->name);
778 kfree(device);
779 ret = 0;
780 goto out;
781
782error_brelse:
783 brelse(bh);
784error_close:
785 close_bdev_excl(bdev);
786out:
787 mutex_unlock(&uuid_mutex);
788 mutex_unlock(&root->fs_info->fs_mutex);
789 return ret;
790}
791
596int btrfs_init_new_device(struct btrfs_root *root, char *device_path) 792int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
597{ 793{
598 struct btrfs_trans_handle *trans; 794 struct btrfs_trans_handle *trans;
@@ -831,13 +1027,17 @@ int btrfs_relocate_chunk(struct btrfs_root *root,
831 em = lookup_extent_mapping(em_tree, chunk_offset, 1); 1027 em = lookup_extent_mapping(em_tree, chunk_offset, 1);
832 spin_unlock(&em_tree->lock); 1028 spin_unlock(&em_tree->lock);
833 1029
834 BUG_ON(em->start > chunk_offset || em->start + em->len < chunk_offset); 1030 BUG_ON(em->start > chunk_offset ||
1031 em->start + em->len < chunk_offset);
835 map = (struct map_lookup *)em->bdev; 1032 map = (struct map_lookup *)em->bdev;
836 1033
837 for (i = 0; i < map->num_stripes; i++) { 1034 for (i = 0; i < map->num_stripes; i++) {
838 ret = btrfs_free_dev_extent(trans, map->stripes[i].dev, 1035 ret = btrfs_free_dev_extent(trans, map->stripes[i].dev,
839 map->stripes[i].physical); 1036 map->stripes[i].physical);
840 BUG_ON(ret); 1037 BUG_ON(ret);
1038
1039 ret = btrfs_update_device(trans, map->stripes[i].dev);
1040 BUG_ON(ret);
841 } 1041 }
842 ret = btrfs_free_chunk(trans, root, chunk_tree, chunk_objectid, 1042 ret = btrfs_free_chunk(trans, root, chunk_tree, chunk_objectid,
843 chunk_offset); 1043 chunk_offset);
@@ -847,11 +1047,8 @@ int btrfs_relocate_chunk(struct btrfs_root *root,
847 if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) { 1047 if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) {
848 ret = btrfs_del_sys_chunk(root, chunk_objectid, chunk_offset); 1048 ret = btrfs_del_sys_chunk(root, chunk_objectid, chunk_offset);
849 BUG_ON(ret); 1049 BUG_ON(ret);
850 goto out;
851 } 1050 }
852 1051
853
854
855 spin_lock(&em_tree->lock); 1052 spin_lock(&em_tree->lock);
856 remove_extent_mapping(em_tree, em); 1053 remove_extent_mapping(em_tree, em);
857 kfree(map); 1054 kfree(map);
@@ -861,7 +1058,6 @@ int btrfs_relocate_chunk(struct btrfs_root *root,
861 free_extent_map(em); 1058 free_extent_map(em);
862 spin_unlock(&em_tree->lock); 1059 spin_unlock(&em_tree->lock);
863 1060
864out:
865 /* once for us */ 1061 /* once for us */
866 free_extent_map(em); 1062 free_extent_map(em);
867 1063
@@ -1449,7 +1645,7 @@ again:
1449 return 0; 1645 return 0;
1450 1646
1451 if (!em) { 1647 if (!em) {
1452 printk("unable to find logical %Lu\n", logical); 1648 printk("unable to find logical %Lu len %Lu\n", logical, *length);
1453 BUG(); 1649 BUG();
1454 } 1650 }
1455 1651
@@ -1712,6 +1908,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
1712 1908
1713 logical = key->offset; 1909 logical = key->offset;
1714 length = btrfs_chunk_length(leaf, chunk); 1910 length = btrfs_chunk_length(leaf, chunk);
1911
1715 spin_lock(&map_tree->map_tree.lock); 1912 spin_lock(&map_tree->map_tree.lock);
1716 em = lookup_extent_mapping(&map_tree->map_tree, logical, 1); 1913 em = lookup_extent_mapping(&map_tree->map_tree, logical, 1);
1717 spin_unlock(&map_tree->map_tree.lock); 1914 spin_unlock(&map_tree->map_tree.lock);
@@ -1845,7 +2042,7 @@ int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf)
1845int btrfs_read_sys_array(struct btrfs_root *root) 2042int btrfs_read_sys_array(struct btrfs_root *root)
1846{ 2043{
1847 struct btrfs_super_block *super_copy = &root->fs_info->super_copy; 2044 struct btrfs_super_block *super_copy = &root->fs_info->super_copy;
1848 struct extent_buffer *sb = root->fs_info->sb_buffer; 2045 struct extent_buffer *sb;
1849 struct btrfs_disk_key *disk_key; 2046 struct btrfs_disk_key *disk_key;
1850 struct btrfs_chunk *chunk; 2047 struct btrfs_chunk *chunk;
1851 u8 *ptr; 2048 u8 *ptr;
@@ -1857,6 +2054,12 @@ int btrfs_read_sys_array(struct btrfs_root *root)
1857 u32 cur; 2054 u32 cur;
1858 struct btrfs_key key; 2055 struct btrfs_key key;
1859 2056
2057 sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET,
2058 BTRFS_SUPER_INFO_SIZE);
2059 if (!sb)
2060 return -ENOMEM;
2061 btrfs_set_buffer_uptodate(sb);
2062 write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE);
1860 array_size = btrfs_super_sys_array_size(super_copy); 2063 array_size = btrfs_super_sys_array_size(super_copy);
1861 2064
1862 ptr = super_copy->sys_chunk_array; 2065 ptr = super_copy->sys_chunk_array;
@@ -1867,8 +2070,7 @@ int btrfs_read_sys_array(struct btrfs_root *root)
1867 disk_key = (struct btrfs_disk_key *)ptr; 2070 disk_key = (struct btrfs_disk_key *)ptr;
1868 btrfs_disk_key_to_cpu(&key, disk_key); 2071 btrfs_disk_key_to_cpu(&key, disk_key);
1869 2072
1870 len = sizeof(*disk_key); 2073 len = sizeof(*disk_key); ptr += len;
1871 ptr += len;
1872 sb_ptr += len; 2074 sb_ptr += len;
1873 cur += len; 2075 cur += len;
1874 2076
@@ -1887,6 +2089,7 @@ int btrfs_read_sys_array(struct btrfs_root *root)
1887 sb_ptr += len; 2089 sb_ptr += len;
1888 cur += len; 2090 cur += len;
1889 } 2091 }
2092 free_extent_buffer(sb);
1890 return ret; 2093 return ret;
1891} 2094}
1892 2095