diff options
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 221 |
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 { | |||
45 | static DEFINE_MUTEX(uuid_mutex); | 45 | static DEFINE_MUTEX(uuid_mutex); |
46 | static LIST_HEAD(fs_uuids); | 46 | static LIST_HEAD(fs_uuids); |
47 | 47 | ||
48 | void btrfs_lock_volumes(void) | ||
49 | { | ||
50 | mutex_lock(&uuid_mutex); | ||
51 | } | ||
52 | |||
53 | void btrfs_unlock_volumes(void) | ||
54 | { | ||
55 | mutex_unlock(&uuid_mutex); | ||
56 | } | ||
57 | |||
48 | int btrfs_cleanup_fs_uuids(void) | 58 | int 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 | ||
628 | static 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); | ||
688 | out: | ||
689 | btrfs_free_path(path); | ||
690 | btrfs_commit_transaction(trans, root); | ||
691 | return ret; | ||
692 | } | ||
693 | |||
694 | int 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 | |||
782 | error_brelse: | ||
783 | brelse(bh); | ||
784 | error_close: | ||
785 | close_bdev_excl(bdev); | ||
786 | out: | ||
787 | mutex_unlock(&uuid_mutex); | ||
788 | mutex_unlock(&root->fs_info->fs_mutex); | ||
789 | return ret; | ||
790 | } | ||
791 | |||
596 | int btrfs_init_new_device(struct btrfs_root *root, char *device_path) | 792 | int 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 | ||
864 | out: | ||
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) | |||
1845 | int btrfs_read_sys_array(struct btrfs_root *root) | 2042 | int 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 | ||