diff options
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 87 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 75 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 3 |
4 files changed, 148 insertions, 18 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index bc57e236ac64..2b15fb97d23f 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -2006,6 +2006,7 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | |||
2006 | int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr); | 2006 | int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr); |
2007 | int btrfs_free_block_groups(struct btrfs_fs_info *info); | 2007 | int btrfs_free_block_groups(struct btrfs_fs_info *info); |
2008 | int btrfs_read_block_groups(struct btrfs_root *root); | 2008 | int btrfs_read_block_groups(struct btrfs_root *root); |
2009 | int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr); | ||
2009 | int btrfs_make_block_group(struct btrfs_trans_handle *trans, | 2010 | int btrfs_make_block_group(struct btrfs_trans_handle *trans, |
2010 | struct btrfs_root *root, u64 bytes_used, | 2011 | struct btrfs_root *root, u64 bytes_used, |
2011 | u64 type, u64 chunk_objectid, u64 chunk_offset, | 2012 | u64 type, u64 chunk_objectid, u64 chunk_offset, |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 4bd04f3fa8bb..4c7c9467f224 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -7402,6 +7402,93 @@ out: | |||
7402 | } | 7402 | } |
7403 | #endif | 7403 | #endif |
7404 | 7404 | ||
7405 | /* | ||
7406 | * checks to see if its even possible to relocate this block group. | ||
7407 | * | ||
7408 | * @return - -1 if it's not a good idea to relocate this block group, 0 if its | ||
7409 | * ok to go ahead and try. | ||
7410 | */ | ||
7411 | int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) | ||
7412 | { | ||
7413 | struct btrfs_block_group_cache *block_group; | ||
7414 | struct btrfs_space_info *space_info; | ||
7415 | struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; | ||
7416 | struct btrfs_device *device; | ||
7417 | int full = 0; | ||
7418 | int ret = 0; | ||
7419 | |||
7420 | block_group = btrfs_lookup_block_group(root->fs_info, bytenr); | ||
7421 | |||
7422 | /* odd, couldn't find the block group, leave it alone */ | ||
7423 | if (!block_group) | ||
7424 | return -1; | ||
7425 | |||
7426 | /* no bytes used, we're good */ | ||
7427 | if (!btrfs_block_group_used(&block_group->item)) | ||
7428 | goto out; | ||
7429 | |||
7430 | space_info = block_group->space_info; | ||
7431 | spin_lock(&space_info->lock); | ||
7432 | |||
7433 | full = space_info->full; | ||
7434 | |||
7435 | /* | ||
7436 | * if this is the last block group we have in this space, we can't | ||
7437 | * relocate it. | ||
7438 | */ | ||
7439 | if (space_info->total_bytes == block_group->key.offset) { | ||
7440 | ret = -1; | ||
7441 | spin_unlock(&space_info->lock); | ||
7442 | goto out; | ||
7443 | } | ||
7444 | |||
7445 | /* | ||
7446 | * need to make sure we have room in the space to handle all of the | ||
7447 | * extents from this block group. If we can, we're good | ||
7448 | */ | ||
7449 | if (space_info->bytes_used + space_info->bytes_reserved + | ||
7450 | space_info->bytes_pinned + space_info->bytes_readonly + | ||
7451 | btrfs_block_group_used(&block_group->item) < | ||
7452 | space_info->total_bytes) { | ||
7453 | spin_unlock(&space_info->lock); | ||
7454 | goto out; | ||
7455 | } | ||
7456 | spin_unlock(&space_info->lock); | ||
7457 | |||
7458 | /* | ||
7459 | * ok we don't have enough space, but maybe we have free space on our | ||
7460 | * devices to allocate new chunks for relocation, so loop through our | ||
7461 | * alloc devices and guess if we have enough space. However, if we | ||
7462 | * were marked as full, then we know there aren't enough chunks, and we | ||
7463 | * can just return. | ||
7464 | */ | ||
7465 | ret = -1; | ||
7466 | if (full) | ||
7467 | goto out; | ||
7468 | |||
7469 | mutex_lock(&root->fs_info->chunk_mutex); | ||
7470 | list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) { | ||
7471 | u64 min_free = btrfs_block_group_used(&block_group->item); | ||
7472 | u64 dev_offset, max_avail; | ||
7473 | |||
7474 | /* | ||
7475 | * check to make sure we can actually find a chunk with enough | ||
7476 | * space to fit our block group in. | ||
7477 | */ | ||
7478 | if (device->total_bytes > device->bytes_used + min_free) { | ||
7479 | ret = find_free_dev_extent(NULL, device, min_free, | ||
7480 | &dev_offset, &max_avail); | ||
7481 | if (!ret) | ||
7482 | break; | ||
7483 | ret = -1; | ||
7484 | } | ||
7485 | } | ||
7486 | mutex_unlock(&root->fs_info->chunk_mutex); | ||
7487 | out: | ||
7488 | btrfs_put_block_group(block_group); | ||
7489 | return ret; | ||
7490 | } | ||
7491 | |||
7405 | static int find_first_block_group(struct btrfs_root *root, | 7492 | static int find_first_block_group(struct btrfs_root *root, |
7406 | struct btrfs_path *path, struct btrfs_key *key) | 7493 | struct btrfs_path *path, struct btrfs_key *key) |
7407 | { | 7494 | { |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index d2358c06bbd9..be953afe804c 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -719,10 +719,9 @@ error: | |||
719 | * called very infrequently and that a given device has a small number | 719 | * called very infrequently and that a given device has a small number |
720 | * of extents | 720 | * of extents |
721 | */ | 721 | */ |
722 | static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans, | 722 | int find_free_dev_extent(struct btrfs_trans_handle *trans, |
723 | struct btrfs_device *device, | 723 | struct btrfs_device *device, u64 num_bytes, |
724 | u64 num_bytes, u64 *start, | 724 | u64 *start, u64 *max_avail) |
725 | u64 *max_avail) | ||
726 | { | 725 | { |
727 | struct btrfs_key key; | 726 | struct btrfs_key key; |
728 | struct btrfs_root *root = device->dev_root; | 727 | struct btrfs_root *root = device->dev_root; |
@@ -1736,6 +1735,10 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, | |||
1736 | extent_root = root->fs_info->extent_root; | 1735 | extent_root = root->fs_info->extent_root; |
1737 | em_tree = &root->fs_info->mapping_tree.map_tree; | 1736 | em_tree = &root->fs_info->mapping_tree.map_tree; |
1738 | 1737 | ||
1738 | ret = btrfs_can_relocate(extent_root, chunk_offset); | ||
1739 | if (ret) | ||
1740 | return -ENOSPC; | ||
1741 | |||
1739 | /* step one, relocate all the extents inside this chunk */ | 1742 | /* step one, relocate all the extents inside this chunk */ |
1740 | ret = btrfs_relocate_block_group(extent_root, chunk_offset); | 1743 | ret = btrfs_relocate_block_group(extent_root, chunk_offset); |
1741 | BUG_ON(ret); | 1744 | BUG_ON(ret); |
@@ -1807,12 +1810,15 @@ static int btrfs_relocate_sys_chunks(struct btrfs_root *root) | |||
1807 | struct btrfs_key found_key; | 1810 | struct btrfs_key found_key; |
1808 | u64 chunk_tree = chunk_root->root_key.objectid; | 1811 | u64 chunk_tree = chunk_root->root_key.objectid; |
1809 | u64 chunk_type; | 1812 | u64 chunk_type; |
1813 | bool retried = false; | ||
1814 | int failed = 0; | ||
1810 | int ret; | 1815 | int ret; |
1811 | 1816 | ||
1812 | path = btrfs_alloc_path(); | 1817 | path = btrfs_alloc_path(); |
1813 | if (!path) | 1818 | if (!path) |
1814 | return -ENOMEM; | 1819 | return -ENOMEM; |
1815 | 1820 | ||
1821 | again: | ||
1816 | key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; | 1822 | key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; |
1817 | key.offset = (u64)-1; | 1823 | key.offset = (u64)-1; |
1818 | key.type = BTRFS_CHUNK_ITEM_KEY; | 1824 | key.type = BTRFS_CHUNK_ITEM_KEY; |
@@ -1842,7 +1848,10 @@ static int btrfs_relocate_sys_chunks(struct btrfs_root *root) | |||
1842 | ret = btrfs_relocate_chunk(chunk_root, chunk_tree, | 1848 | ret = btrfs_relocate_chunk(chunk_root, chunk_tree, |
1843 | found_key.objectid, | 1849 | found_key.objectid, |
1844 | found_key.offset); | 1850 | found_key.offset); |
1845 | BUG_ON(ret); | 1851 | if (ret == -ENOSPC) |
1852 | failed++; | ||
1853 | else if (ret) | ||
1854 | BUG(); | ||
1846 | } | 1855 | } |
1847 | 1856 | ||
1848 | if (found_key.offset == 0) | 1857 | if (found_key.offset == 0) |
@@ -1850,6 +1859,14 @@ static int btrfs_relocate_sys_chunks(struct btrfs_root *root) | |||
1850 | key.offset = found_key.offset - 1; | 1859 | key.offset = found_key.offset - 1; |
1851 | } | 1860 | } |
1852 | ret = 0; | 1861 | ret = 0; |
1862 | if (failed && !retried) { | ||
1863 | failed = 0; | ||
1864 | retried = true; | ||
1865 | goto again; | ||
1866 | } else if (failed && retried) { | ||
1867 | WARN_ON(1); | ||
1868 | ret = -ENOSPC; | ||
1869 | } | ||
1853 | error: | 1870 | error: |
1854 | btrfs_free_path(path); | 1871 | btrfs_free_path(path); |
1855 | return ret; | 1872 | return ret; |
@@ -1894,6 +1911,8 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
1894 | continue; | 1911 | continue; |
1895 | 1912 | ||
1896 | ret = btrfs_shrink_device(device, old_size - size_to_free); | 1913 | ret = btrfs_shrink_device(device, old_size - size_to_free); |
1914 | if (ret == -ENOSPC) | ||
1915 | break; | ||
1897 | BUG_ON(ret); | 1916 | BUG_ON(ret); |
1898 | 1917 | ||
1899 | trans = btrfs_start_transaction(dev_root, 1); | 1918 | trans = btrfs_start_transaction(dev_root, 1); |
@@ -1938,9 +1957,8 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
1938 | chunk = btrfs_item_ptr(path->nodes[0], | 1957 | chunk = btrfs_item_ptr(path->nodes[0], |
1939 | path->slots[0], | 1958 | path->slots[0], |
1940 | struct btrfs_chunk); | 1959 | struct btrfs_chunk); |
1941 | key.offset = found_key.offset; | ||
1942 | /* chunk zero is special */ | 1960 | /* chunk zero is special */ |
1943 | if (key.offset == 0) | 1961 | if (found_key.offset == 0) |
1944 | break; | 1962 | break; |
1945 | 1963 | ||
1946 | btrfs_release_path(chunk_root, path); | 1964 | btrfs_release_path(chunk_root, path); |
@@ -1948,7 +1966,8 @@ int btrfs_balance(struct btrfs_root *dev_root) | |||
1948 | chunk_root->root_key.objectid, | 1966 | chunk_root->root_key.objectid, |
1949 | found_key.objectid, | 1967 | found_key.objectid, |
1950 | found_key.offset); | 1968 | found_key.offset); |
1951 | BUG_ON(ret); | 1969 | BUG_ON(ret && ret != -ENOSPC); |
1970 | key.offset = found_key.offset - 1; | ||
1952 | } | 1971 | } |
1953 | ret = 0; | 1972 | ret = 0; |
1954 | error: | 1973 | error: |
@@ -1974,10 +1993,13 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) | |||
1974 | u64 chunk_offset; | 1993 | u64 chunk_offset; |
1975 | int ret; | 1994 | int ret; |
1976 | int slot; | 1995 | int slot; |
1996 | int failed = 0; | ||
1997 | bool retried = false; | ||
1977 | struct extent_buffer *l; | 1998 | struct extent_buffer *l; |
1978 | struct btrfs_key key; | 1999 | struct btrfs_key key; |
1979 | struct btrfs_super_block *super_copy = &root->fs_info->super_copy; | 2000 | struct btrfs_super_block *super_copy = &root->fs_info->super_copy; |
1980 | u64 old_total = btrfs_super_total_bytes(super_copy); | 2001 | u64 old_total = btrfs_super_total_bytes(super_copy); |
2002 | u64 old_size = device->total_bytes; | ||
1981 | u64 diff = device->total_bytes - new_size; | 2003 | u64 diff = device->total_bytes - new_size; |
1982 | 2004 | ||
1983 | if (new_size >= device->total_bytes) | 2005 | if (new_size >= device->total_bytes) |
@@ -1987,12 +2009,6 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) | |||
1987 | if (!path) | 2009 | if (!path) |
1988 | return -ENOMEM; | 2010 | return -ENOMEM; |
1989 | 2011 | ||
1990 | trans = btrfs_start_transaction(root, 1); | ||
1991 | if (!trans) { | ||
1992 | ret = -ENOMEM; | ||
1993 | goto done; | ||
1994 | } | ||
1995 | |||
1996 | path->reada = 2; | 2012 | path->reada = 2; |
1997 | 2013 | ||
1998 | lock_chunks(root); | 2014 | lock_chunks(root); |
@@ -2001,8 +2017,8 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) | |||
2001 | if (device->writeable) | 2017 | if (device->writeable) |
2002 | device->fs_devices->total_rw_bytes -= diff; | 2018 | device->fs_devices->total_rw_bytes -= diff; |
2003 | unlock_chunks(root); | 2019 | unlock_chunks(root); |
2004 | btrfs_end_transaction(trans, root); | ||
2005 | 2020 | ||
2021 | again: | ||
2006 | key.objectid = device->devid; | 2022 | key.objectid = device->devid; |
2007 | key.offset = (u64)-1; | 2023 | key.offset = (u64)-1; |
2008 | key.type = BTRFS_DEV_EXTENT_KEY; | 2024 | key.type = BTRFS_DEV_EXTENT_KEY; |
@@ -2017,6 +2033,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) | |||
2017 | goto done; | 2033 | goto done; |
2018 | if (ret) { | 2034 | if (ret) { |
2019 | ret = 0; | 2035 | ret = 0; |
2036 | btrfs_release_path(root, path); | ||
2020 | break; | 2037 | break; |
2021 | } | 2038 | } |
2022 | 2039 | ||
@@ -2024,14 +2041,18 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) | |||
2024 | slot = path->slots[0]; | 2041 | slot = path->slots[0]; |
2025 | btrfs_item_key_to_cpu(l, &key, path->slots[0]); | 2042 | btrfs_item_key_to_cpu(l, &key, path->slots[0]); |
2026 | 2043 | ||
2027 | if (key.objectid != device->devid) | 2044 | if (key.objectid != device->devid) { |
2045 | btrfs_release_path(root, path); | ||
2028 | break; | 2046 | break; |
2047 | } | ||
2029 | 2048 | ||
2030 | dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); | 2049 | dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); |
2031 | length = btrfs_dev_extent_length(l, dev_extent); | 2050 | length = btrfs_dev_extent_length(l, dev_extent); |
2032 | 2051 | ||
2033 | if (key.offset + length <= new_size) | 2052 | if (key.offset + length <= new_size) { |
2053 | btrfs_release_path(root, path); | ||
2034 | break; | 2054 | break; |
2055 | } | ||
2035 | 2056 | ||
2036 | chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent); | 2057 | chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent); |
2037 | chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent); | 2058 | chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent); |
@@ -2040,8 +2061,26 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) | |||
2040 | 2061 | ||
2041 | ret = btrfs_relocate_chunk(root, chunk_tree, chunk_objectid, | 2062 | ret = btrfs_relocate_chunk(root, chunk_tree, chunk_objectid, |
2042 | chunk_offset); | 2063 | chunk_offset); |
2043 | if (ret) | 2064 | if (ret && ret != -ENOSPC) |
2044 | goto done; | 2065 | goto done; |
2066 | if (ret == -ENOSPC) | ||
2067 | failed++; | ||
2068 | key.offset -= 1; | ||
2069 | } | ||
2070 | |||
2071 | if (failed && !retried) { | ||
2072 | failed = 0; | ||
2073 | retried = true; | ||
2074 | goto again; | ||
2075 | } else if (failed && retried) { | ||
2076 | ret = -ENOSPC; | ||
2077 | lock_chunks(root); | ||
2078 | |||
2079 | device->total_bytes = old_size; | ||
2080 | if (device->writeable) | ||
2081 | device->fs_devices->total_rw_bytes += diff; | ||
2082 | unlock_chunks(root); | ||
2083 | goto done; | ||
2045 | } | 2084 | } |
2046 | 2085 | ||
2047 | /* Shrinking succeeded, else we would be at "done". */ | 2086 | /* Shrinking succeeded, else we would be at "done". */ |
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 5139a833f721..31b0fabdd2ea 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
@@ -181,4 +181,7 @@ int btrfs_balance(struct btrfs_root *dev_root); | |||
181 | void btrfs_unlock_volumes(void); | 181 | void btrfs_unlock_volumes(void); |
182 | void btrfs_lock_volumes(void); | 182 | void btrfs_lock_volumes(void); |
183 | int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); | 183 | int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); |
184 | int find_free_dev_extent(struct btrfs_trans_handle *trans, | ||
185 | struct btrfs_device *device, u64 num_bytes, | ||
186 | u64 *start, u64 *max_avail); | ||
184 | #endif | 187 | #endif |