diff options
Diffstat (limited to 'fs/btrfs/free-space-cache.c')
-rw-r--r-- | fs/btrfs/free-space-cache.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index f03ef97c3b21..0037427d8a9d 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c | |||
@@ -2178,3 +2178,95 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster) | |||
2178 | cluster->block_group = NULL; | 2178 | cluster->block_group = NULL; |
2179 | } | 2179 | } |
2180 | 2180 | ||
2181 | int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, | ||
2182 | u64 *trimmed, u64 start, u64 end, u64 minlen) | ||
2183 | { | ||
2184 | struct btrfs_free_space *entry = NULL; | ||
2185 | struct btrfs_fs_info *fs_info = block_group->fs_info; | ||
2186 | u64 bytes = 0; | ||
2187 | u64 actually_trimmed; | ||
2188 | int ret = 0; | ||
2189 | |||
2190 | *trimmed = 0; | ||
2191 | |||
2192 | while (start < end) { | ||
2193 | spin_lock(&block_group->tree_lock); | ||
2194 | |||
2195 | if (block_group->free_space < minlen) { | ||
2196 | spin_unlock(&block_group->tree_lock); | ||
2197 | break; | ||
2198 | } | ||
2199 | |||
2200 | entry = tree_search_offset(block_group, start, 0, 1); | ||
2201 | if (!entry) | ||
2202 | entry = tree_search_offset(block_group, | ||
2203 | offset_to_bitmap(block_group, | ||
2204 | start), | ||
2205 | 1, 1); | ||
2206 | |||
2207 | if (!entry || entry->offset >= end) { | ||
2208 | spin_unlock(&block_group->tree_lock); | ||
2209 | break; | ||
2210 | } | ||
2211 | |||
2212 | if (entry->bitmap) { | ||
2213 | ret = search_bitmap(block_group, entry, &start, &bytes); | ||
2214 | if (!ret) { | ||
2215 | if (start >= end) { | ||
2216 | spin_unlock(&block_group->tree_lock); | ||
2217 | break; | ||
2218 | } | ||
2219 | bytes = min(bytes, end - start); | ||
2220 | bitmap_clear_bits(block_group, entry, | ||
2221 | start, bytes); | ||
2222 | if (entry->bytes == 0) | ||
2223 | free_bitmap(block_group, entry); | ||
2224 | } else { | ||
2225 | start = entry->offset + BITS_PER_BITMAP * | ||
2226 | block_group->sectorsize; | ||
2227 | spin_unlock(&block_group->tree_lock); | ||
2228 | ret = 0; | ||
2229 | continue; | ||
2230 | } | ||
2231 | } else { | ||
2232 | start = entry->offset; | ||
2233 | bytes = min(entry->bytes, end - start); | ||
2234 | unlink_free_space(block_group, entry); | ||
2235 | kfree(entry); | ||
2236 | } | ||
2237 | |||
2238 | spin_unlock(&block_group->tree_lock); | ||
2239 | |||
2240 | if (bytes >= minlen) { | ||
2241 | int update_ret; | ||
2242 | update_ret = btrfs_update_reserved_bytes(block_group, | ||
2243 | bytes, 1, 1); | ||
2244 | |||
2245 | ret = btrfs_error_discard_extent(fs_info->extent_root, | ||
2246 | start, | ||
2247 | bytes, | ||
2248 | &actually_trimmed); | ||
2249 | |||
2250 | btrfs_add_free_space(block_group, | ||
2251 | start, bytes); | ||
2252 | if (!update_ret) | ||
2253 | btrfs_update_reserved_bytes(block_group, | ||
2254 | bytes, 0, 1); | ||
2255 | |||
2256 | if (ret) | ||
2257 | break; | ||
2258 | *trimmed += actually_trimmed; | ||
2259 | } | ||
2260 | start += bytes; | ||
2261 | bytes = 0; | ||
2262 | |||
2263 | if (fatal_signal_pending(current)) { | ||
2264 | ret = -ERESTARTSYS; | ||
2265 | break; | ||
2266 | } | ||
2267 | |||
2268 | cond_resched(); | ||
2269 | } | ||
2270 | |||
2271 | return ret; | ||
2272 | } | ||