diff options
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 75 |
1 files changed, 57 insertions, 18 deletions
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". */ |