diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/extent-tree.c | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index e11875e97c2f..6b5966aacf44 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -2017,26 +2017,49 @@ int btrfs_check_metadata_free_space(struct btrfs_root *root) | |||
2017 | struct btrfs_fs_info *info = root->fs_info; | 2017 | struct btrfs_fs_info *info = root->fs_info; |
2018 | struct btrfs_space_info *meta_sinfo; | 2018 | struct btrfs_space_info *meta_sinfo; |
2019 | u64 alloc_target, thresh; | 2019 | u64 alloc_target, thresh; |
2020 | int committed = 0, ret; | ||
2020 | 2021 | ||
2021 | /* get the space info for where the metadata will live */ | 2022 | /* get the space info for where the metadata will live */ |
2022 | alloc_target = btrfs_get_alloc_profile(root, 0); | 2023 | alloc_target = btrfs_get_alloc_profile(root, 0); |
2023 | meta_sinfo = __find_space_info(info, alloc_target); | 2024 | meta_sinfo = __find_space_info(info, alloc_target); |
2024 | 2025 | ||
2025 | /* | 2026 | again: |
2026 | * if the metadata area isn't maxed out then there is no sense in | ||
2027 | * checking how much is used, since we can always allocate a new chunk | ||
2028 | */ | ||
2029 | if (!meta_sinfo->full) | ||
2030 | return 0; | ||
2031 | |||
2032 | spin_lock(&meta_sinfo->lock); | 2027 | spin_lock(&meta_sinfo->lock); |
2033 | thresh = meta_sinfo->total_bytes * 95; | 2028 | if (!meta_sinfo->full) |
2029 | thresh = meta_sinfo->total_bytes * 80; | ||
2030 | else | ||
2031 | thresh = meta_sinfo->total_bytes * 95; | ||
2034 | 2032 | ||
2035 | do_div(thresh, 100); | 2033 | do_div(thresh, 100); |
2036 | 2034 | ||
2037 | if (meta_sinfo->bytes_used + meta_sinfo->bytes_reserved + | 2035 | if (meta_sinfo->bytes_used + meta_sinfo->bytes_reserved + |
2038 | meta_sinfo->bytes_pinned + meta_sinfo->bytes_readonly > thresh) { | 2036 | meta_sinfo->bytes_pinned + meta_sinfo->bytes_readonly > thresh) { |
2037 | struct btrfs_trans_handle *trans; | ||
2038 | if (!meta_sinfo->full) { | ||
2039 | meta_sinfo->force_alloc = 1; | ||
2040 | spin_unlock(&meta_sinfo->lock); | ||
2041 | |||
2042 | trans = btrfs_start_transaction(root, 1); | ||
2043 | if (!trans) | ||
2044 | return -ENOMEM; | ||
2045 | |||
2046 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, | ||
2047 | 2 * 1024 * 1024, alloc_target, 0); | ||
2048 | btrfs_end_transaction(trans, root); | ||
2049 | goto again; | ||
2050 | } | ||
2039 | spin_unlock(&meta_sinfo->lock); | 2051 | spin_unlock(&meta_sinfo->lock); |
2052 | |||
2053 | if (!committed) { | ||
2054 | committed = 1; | ||
2055 | trans = btrfs_join_transaction(root, 1); | ||
2056 | if (!trans) | ||
2057 | return -ENOMEM; | ||
2058 | ret = btrfs_commit_transaction(trans, root); | ||
2059 | if (ret) | ||
2060 | return ret; | ||
2061 | goto again; | ||
2062 | } | ||
2040 | return -ENOSPC; | 2063 | return -ENOSPC; |
2041 | } | 2064 | } |
2042 | spin_unlock(&meta_sinfo->lock); | 2065 | spin_unlock(&meta_sinfo->lock); |
@@ -2052,7 +2075,7 @@ int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode, | |||
2052 | u64 bytes) | 2075 | u64 bytes) |
2053 | { | 2076 | { |
2054 | struct btrfs_space_info *data_sinfo; | 2077 | struct btrfs_space_info *data_sinfo; |
2055 | int ret = 0; | 2078 | int ret = 0, committed = 0; |
2056 | 2079 | ||
2057 | /* make sure bytes are sectorsize aligned */ | 2080 | /* make sure bytes are sectorsize aligned */ |
2058 | bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1); | 2081 | bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1); |
@@ -2065,13 +2088,14 @@ again: | |||
2065 | data_sinfo->bytes_delalloc - data_sinfo->bytes_reserved - | 2088 | data_sinfo->bytes_delalloc - data_sinfo->bytes_reserved - |
2066 | data_sinfo->bytes_pinned - data_sinfo->bytes_readonly - | 2089 | data_sinfo->bytes_pinned - data_sinfo->bytes_readonly - |
2067 | data_sinfo->bytes_may_use < bytes) { | 2090 | data_sinfo->bytes_may_use < bytes) { |
2091 | struct btrfs_trans_handle *trans; | ||
2092 | |||
2068 | /* | 2093 | /* |
2069 | * if we don't have enough free bytes in this space then we need | 2094 | * if we don't have enough free bytes in this space then we need |
2070 | * to alloc a new chunk. | 2095 | * to alloc a new chunk. |
2071 | */ | 2096 | */ |
2072 | if (!data_sinfo->full) { | 2097 | if (!data_sinfo->full) { |
2073 | u64 alloc_target; | 2098 | u64 alloc_target; |
2074 | struct btrfs_trans_handle *trans; | ||
2075 | 2099 | ||
2076 | data_sinfo->force_alloc = 1; | 2100 | data_sinfo->force_alloc = 1; |
2077 | spin_unlock(&data_sinfo->lock); | 2101 | spin_unlock(&data_sinfo->lock); |
@@ -2090,6 +2114,19 @@ again: | |||
2090 | goto again; | 2114 | goto again; |
2091 | } | 2115 | } |
2092 | spin_unlock(&data_sinfo->lock); | 2116 | spin_unlock(&data_sinfo->lock); |
2117 | |||
2118 | /* commit the current transaction and try again */ | ||
2119 | if (!committed) { | ||
2120 | committed = 1; | ||
2121 | trans = btrfs_join_transaction(root, 1); | ||
2122 | if (!trans) | ||
2123 | return -ENOMEM; | ||
2124 | ret = btrfs_commit_transaction(trans, root); | ||
2125 | if (ret) | ||
2126 | return ret; | ||
2127 | goto again; | ||
2128 | } | ||
2129 | |||
2093 | printk(KERN_ERR "no space left, need %llu, %llu delalloc bytes" | 2130 | printk(KERN_ERR "no space left, need %llu, %llu delalloc bytes" |
2094 | ", %llu bytes_used, %llu bytes_reserved, " | 2131 | ", %llu bytes_used, %llu bytes_reserved, " |
2095 | "%llu bytes_pinned, %llu bytes_readonly, %llu may use" | 2132 | "%llu bytes_pinned, %llu bytes_readonly, %llu may use" |