diff mbox series

[v2,6/6] btrfs: add mode to clear chunk map status to CLEAR_FREE ioctl

Message ID 4208ea4c7e515fe38fd5e3d451180a349a595cf1.1741777050.git.dsterba@suse.com (mailing list archive)
State New
Headers show
Series Ioctl to clear unused space in various ways | expand

Commit Message

David Sterba March 12, 2025, 11:12 a.m. UTC
The trim status is tracked for each chunk in the fs_info::mapping_tree
and updated as trim is called either manually by 'fstrim' or
automatically when discard=async is enabled.

With the new modes it's necessary to allow clearing the cache otherwise
on a fully or partially trimmed filesystem the ioctl won't work as
expected.

Add separate clear free operation to reset just the trim status bits
from all chunks. This should be called namely when the clearing
operation is *not* trim (e.g. zeroout or secure erase).

Signed-off-by: David Sterba <dsterba@suse.com>
---
 fs/btrfs/ioctl.c           | 13 +++++++++++++
 fs/btrfs/volumes.c         |  5 +++++
 fs/btrfs/volumes.h         |  1 +
 include/uapi/linux/btrfs.h |  7 +++++++
 4 files changed, 26 insertions(+)
diff mbox series

Patch

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index e84db3929763..f965f7fc1fa8 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -5235,6 +5235,19 @@  static int btrfs_ioctl_clear_free(struct file *file, void __user *arg)
 	if (args.type >= BTRFS_NR_CLEAR_OP_TYPES)
 		return -EOPNOTSUPP;
 
+	if (args.type == BTRFS_CLEAR_OP_RESET_CHUNK_STATUS_CACHE) {
+		write_lock(&fs_info->mapping_tree_lock);
+		for (struct rb_node *node = rb_first_cached(&fs_info->mapping_tree);
+		     node; node = rb_next(node)) {
+			struct btrfs_chunk_map *map;
+
+			map = rb_entry(node, struct btrfs_chunk_map, rb_node);
+			btrfs_chunk_map_clear_bits(map, CHUNK_TRIMMED);
+		}
+		write_unlock(&fs_info->mapping_tree_lock);
+		return 0;
+	}
+
 	ret = mnt_want_write_file(file);
 	if (ret)
 		return ret;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index f1b1d7446b20..786b93c18a22 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -8079,6 +8079,11 @@  static int verify_chunk_dev_extent_mapping(struct btrfs_fs_info *fs_info)
 	return ret;
 }
 
+void btrfs_chunk_map_clear_bits(struct btrfs_chunk_map *map, unsigned int bits)
+{
+	chunk_map_device_clear_bits(map, bits);
+}
+
 /*
  * Ensure that all dev extents are mapped to correct chunk, otherwise
  * later chunk allocation/free would cause unexpected behavior.
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index e247d551da67..0e793b9776d6 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -785,6 +785,7 @@  struct btrfs_chunk_map *btrfs_find_chunk_map_nolock(struct btrfs_fs_info *fs_inf
 						    u64 logical, u64 length);
 struct btrfs_chunk_map *btrfs_get_chunk_map(struct btrfs_fs_info *fs_info,
 					    u64 logical, u64 length);
+void btrfs_chunk_map_clear_bits(struct btrfs_chunk_map *map, unsigned int bits);
 void btrfs_remove_chunk_map(struct btrfs_fs_info *fs_info, struct btrfs_chunk_map *map);
 void btrfs_release_disk_super(struct btrfs_super_block *super);
 
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index e2f16733c53f..605108ab21f3 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -1119,6 +1119,13 @@  enum btrfs_clear_op_type {
 	BTRFS_CLEAR_OP_ZERO_NOUNMAP,
 	/* Request unmapping the blocks and don't fall back to writing zeros. */
 	BTRFS_CLEAR_OP_ZERO_NOFALLBACK,
+
+	/*
+	 * Only reset status of previously cleared (by any operation) chunks,
+	 * tracked in memory since the last mount. Without that repeated calls
+	 * to clear will skip already processed chunks.
+	 */
+	BTRFS_CLEAR_OP_RESET_CHUNK_STATUS_CACHE,
 	BTRFS_NR_CLEAR_OP_TYPES,
 };