@@ -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;
@@ -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.
@@ -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);
@@ -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,
};
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(+)