|
@@ -2178,3 +2178,95 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster)
|
|
|
cluster->block_group = NULL;
|
|
|
}
|
|
|
|
|
|
+int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
|
|
|
+ u64 *trimmed, u64 start, u64 end, u64 minlen)
|
|
|
+{
|
|
|
+ struct btrfs_free_space *entry = NULL;
|
|
|
+ struct btrfs_fs_info *fs_info = block_group->fs_info;
|
|
|
+ u64 bytes = 0;
|
|
|
+ u64 actually_trimmed;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ *trimmed = 0;
|
|
|
+
|
|
|
+ while (start < end) {
|
|
|
+ spin_lock(&block_group->tree_lock);
|
|
|
+
|
|
|
+ if (block_group->free_space < minlen) {
|
|
|
+ spin_unlock(&block_group->tree_lock);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ entry = tree_search_offset(block_group, start, 0, 1);
|
|
|
+ if (!entry)
|
|
|
+ entry = tree_search_offset(block_group,
|
|
|
+ offset_to_bitmap(block_group,
|
|
|
+ start),
|
|
|
+ 1, 1);
|
|
|
+
|
|
|
+ if (!entry || entry->offset >= end) {
|
|
|
+ spin_unlock(&block_group->tree_lock);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (entry->bitmap) {
|
|
|
+ ret = search_bitmap(block_group, entry, &start, &bytes);
|
|
|
+ if (!ret) {
|
|
|
+ if (start >= end) {
|
|
|
+ spin_unlock(&block_group->tree_lock);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ bytes = min(bytes, end - start);
|
|
|
+ bitmap_clear_bits(block_group, entry,
|
|
|
+ start, bytes);
|
|
|
+ if (entry->bytes == 0)
|
|
|
+ free_bitmap(block_group, entry);
|
|
|
+ } else {
|
|
|
+ start = entry->offset + BITS_PER_BITMAP *
|
|
|
+ block_group->sectorsize;
|
|
|
+ spin_unlock(&block_group->tree_lock);
|
|
|
+ ret = 0;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ start = entry->offset;
|
|
|
+ bytes = min(entry->bytes, end - start);
|
|
|
+ unlink_free_space(block_group, entry);
|
|
|
+ kfree(entry);
|
|
|
+ }
|
|
|
+
|
|
|
+ spin_unlock(&block_group->tree_lock);
|
|
|
+
|
|
|
+ if (bytes >= minlen) {
|
|
|
+ int update_ret;
|
|
|
+ update_ret = btrfs_update_reserved_bytes(block_group,
|
|
|
+ bytes, 1, 1);
|
|
|
+
|
|
|
+ ret = btrfs_error_discard_extent(fs_info->extent_root,
|
|
|
+ start,
|
|
|
+ bytes,
|
|
|
+ &actually_trimmed);
|
|
|
+
|
|
|
+ btrfs_add_free_space(block_group,
|
|
|
+ start, bytes);
|
|
|
+ if (!update_ret)
|
|
|
+ btrfs_update_reserved_bytes(block_group,
|
|
|
+ bytes, 0, 1);
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ break;
|
|
|
+ *trimmed += actually_trimmed;
|
|
|
+ }
|
|
|
+ start += bytes;
|
|
|
+ bytes = 0;
|
|
|
+
|
|
|
+ if (fatal_signal_pending(current)) {
|
|
|
+ ret = -ERESTARTSYS;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ cond_resched();
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|