All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] Add ioctl to clear unused space
@ 2018-04-20 14:21 David Sterba
  2018-04-20 14:21 ` [PATCH 1/6] btrfs: extend trim callchain to pass the operation type David Sterba
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: David Sterba @ 2018-04-20 14:21 UTC (permalink / raw)
  To: linux-btrfs; +Cc: David Sterba

This patchset adds new ioctl similar to TRIM, that provides several
other ways how to clear the unused space.  The changelogs are
incomplete, for preview not for inclusion yet.

It compiles and has been tested lightly, the clearing modes depend on hw
capabilities (secure discard, sector unmapping instead of zeros), so
I've tested only zeroing and discard.

I personally think the zeroing has a usecase and the other modes were
easy to add. Further extensions can be considered, eg. WRITE_SAME,
overwriting with a randomly generated pattern, or some filesystem canary
patterns that can be used to report unused block read as metadata.

As this is modelled after the generic FITRIM ioctl, so this could be a
new generic ioctl too. However, last time somebody wanted such ioctl,
there was a pushback. I'll consider making a generic version and send it
for comments to fsdevel eventually.

git://github.com/kdave/btrfs-devel dev/zero-free


David Sterba (6):
  btrfs: extend trim callchain to pass the operation type
  btrfs: add wrapper to switch clearing operation
  btrfs: add zeroing clear operation
  btrfs: add new ioctl BTRFS_IOC_CLEAR_FREE
  btrfs: add discard secure to clear unused space
  btrfs: add more zeroout modes for clearing unused space

 fs/btrfs/ctree.h            |   5 +-
 fs/btrfs/extent-tree.c      | 130 ++++++++++++++++++++++++++++++++++++++------
 fs/btrfs/free-space-cache.c |  22 +++++---
 fs/btrfs/free-space-cache.h |   3 +-
 fs/btrfs/ioctl.c            |  42 ++++++++++++++
 include/uapi/linux/btrfs.h  |  26 +++++++++
 6 files changed, 199 insertions(+), 29 deletions(-)

-- 
2.16.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/6] btrfs: extend trim callchain to pass the operation type
  2018-04-20 14:21 [PATCH 0/6] Add ioctl to clear unused space David Sterba
@ 2018-04-20 14:21 ` David Sterba
  2018-04-20 14:21 ` [PATCH 2/6] btrfs: add wrapper to switch clearing operation David Sterba
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Sterba @ 2018-04-20 14:21 UTC (permalink / raw)
  To: linux-btrfs; +Cc: David Sterba

This is preparatory work to implement clearing free space by zeroing,
much in the same way the FITRIM ioctl works.  This patch simply defines
a symbolic name for the current clearing operation and passes the
parameter around. No functional change.

Signed-off-by: David Sterba <dsterba@suse.com>
---
 fs/btrfs/ctree.h            | 11 ++++++++-
 fs/btrfs/extent-tree.c      | 54 +++++++++++++++++++++++++++++++--------------
 fs/btrfs/free-space-cache.c | 22 ++++++++++--------
 fs/btrfs/free-space-cache.h |  3 ++-
 4 files changed, 62 insertions(+), 28 deletions(-)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 5474ef14d6e6..7cde72683b8e 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -674,6 +674,14 @@ struct btrfs_stripe_hash {
 	spinlock_t lock;
 };
 
+/*
+ * Type of operation that will be used to clear unused blocks.
+ */
+enum btrfs_clear_op_type {
+	BTRFS_CLEAR_OP_DISCARD = 0,
+	BTRFS_NR_CLEAR_OP_TYPES,
+};
+
 /* used by the raid56 code to lock stripes for read/modify/write */
 struct btrfs_stripe_hash_table {
 	struct list_head stripe_cache;
@@ -2789,7 +2797,8 @@ u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo);
 int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,
 				   u64 start, u64 end);
 int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
-			 u64 num_bytes, u64 *actual_bytes);
+			 u64 num_bytes, u64 *actual_bytes,
+			 enum btrfs_clear_op_type clear);
 int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
 			    struct btrfs_fs_info *fs_info, u64 type);
 int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 5bdb5636d552..ffdd3aba508c 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2036,7 +2036,8 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans,
 
 #define in_range(b, first, len)        ((b) >= (first) && (b) < (first) + (len))
 static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len,
-			       u64 *discarded_bytes)
+			       u64 *discarded_bytes,
+			       enum btrfs_clear_op_type clear)
 {
 	int j, ret = 0;
 	u64 bytes_left, end;
@@ -2082,8 +2083,11 @@ static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len,
 		}
 
 		if (size) {
-			ret = blkdev_issue_discard(bdev, start >> 9, size >> 9,
-						   GFP_NOFS, 0);
+			if (clear == BTRFS_CLEAR_OP_DISCARD)
+				ret = blkdev_issue_discard(bdev, start >> 9,
+						size >> 9, GFP_NOFS, 0);
+			else
+				ret = -EOPNOTSUPP;
 			if (!ret)
 				*discarded_bytes += size;
 			else if (ret != -EOPNOTSUPP)
@@ -2099,8 +2103,11 @@ static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len,
 	}
 
 	if (bytes_left) {
-		ret = blkdev_issue_discard(bdev, start >> 9, bytes_left >> 9,
-					   GFP_NOFS, 0);
+		if (clear == BTRFS_CLEAR_OP_DISCARD)
+			ret = blkdev_issue_discard(bdev, start >> 9,
+					bytes_left >> 9, GFP_NOFS, 0);
+		else
+			ret = -EOPNOTSUPP;
 		if (!ret)
 			*discarded_bytes += bytes_left;
 	}
@@ -2108,12 +2115,18 @@ static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len,
 }
 
 int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
-			 u64 num_bytes, u64 *actual_bytes)
+			 u64 num_bytes, u64 *actual_bytes,
+			 enum btrfs_clear_op_type clear)
 {
 	int ret;
 	u64 discarded_bytes = 0;
 	struct btrfs_bio *bbio = NULL;
+	int rw;
 
+	if (clear == BTRFS_CLEAR_OP_DISCARD)
+		rw = BTRFS_MAP_DISCARD;
+	else
+		rw = BTRFS_MAP_WRITE;
 
 	/*
 	 * Avoid races with device replace and make sure our bbio has devices
@@ -2121,8 +2134,7 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
 	 */
 	btrfs_bio_counter_inc_blocked(fs_info);
 	/* Tell the block device(s) that the sectors can be discarded */
-	ret = btrfs_map_block(fs_info, BTRFS_MAP_DISCARD, bytenr, &num_bytes,
-			      &bbio, 0);
+	ret = btrfs_map_block(fs_info, rw, bytenr, &num_bytes, &bbio, 0);
 	/* Error condition is -ENOMEM */
 	if (!ret) {
 		struct btrfs_bio_stripe *stripe = bbio->stripes;
@@ -2138,13 +2150,14 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
 				continue;
 			}
 			req_q = bdev_get_queue(stripe->dev->bdev);
-			if (!blk_queue_discard(req_q))
+			if (clear == BTRFS_CLEAR_OP_DISCARD &&
+			    !blk_queue_discard(req_q))
 				continue;
 
 			ret = btrfs_issue_discard(stripe->dev->bdev,
 						  stripe->physical,
 						  stripe->length,
-						  &bytes);
+						  &bytes, clear);
 			if (!ret)
 				discarded_bytes += bytes;
 			else if (ret != -EOPNOTSUPP)
@@ -6785,7 +6798,8 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
 
 		if (btrfs_test_opt(fs_info, DISCARD))
 			ret = btrfs_discard_extent(fs_info, start,
-						   end + 1 - start, NULL);
+						   end + 1 - start, NULL,
+						   BTRFS_CLEAR_OP_DISCARD);
 
 		clear_extent_dirty(unpin, start, end);
 		unpin_extent_range(fs_info, start, end, true);
@@ -6807,7 +6821,8 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
 			ret = btrfs_discard_extent(fs_info,
 						   block_group->key.objectid,
 						   block_group->key.offset,
-						   &trimmed);
+						   &trimmed,
+						   BTRFS_CLEAR_OP_DISCARD);
 
 		list_del_init(&block_group->bg_list);
 		btrfs_put_block_group_trimming(block_group);
@@ -8056,7 +8071,8 @@ static int __btrfs_free_reserved_extent(struct btrfs_fs_info *fs_info,
 		pin_down_extent(fs_info, cache, start, len, 1);
 	else {
 		if (btrfs_test_opt(fs_info, DISCARD))
-			ret = btrfs_discard_extent(fs_info, start, len, NULL);
+			ret = btrfs_discard_extent(fs_info, start, len, NULL,
+					BTRFS_CLEAR_OP_DISCARD);
 		btrfs_add_free_space(cache, start, len);
 		btrfs_free_reserved_bytes(cache, len, delalloc);
 		trace_btrfs_reserved_extent_free(fs_info, start, len);
@@ -10892,7 +10908,8 @@ int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,
  * transaction.
  */
 static int btrfs_trim_free_extents(struct btrfs_device *device,
-				   u64 minlen, u64 *trimmed)
+				   u64 minlen, u64 *trimmed,
+				   enum btrfs_clear_op_type clear)
 {
 	u64 start = 0, len = 0;
 	int ret;
@@ -10939,7 +10956,8 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
 			break;
 		}
 
-		ret = btrfs_issue_discard(device->bdev, start, len, &bytes);
+		ret = btrfs_issue_discard(device->bdev, start, len, &bytes,
+				clear);
 		up_read(&fs_info->commit_root_sem);
 		mutex_unlock(&fs_info->chunk_mutex);
 
@@ -11007,7 +11025,8 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
 						     &group_trimmed,
 						     start,
 						     end,
-						     range->minlen);
+						     range->minlen,
+						     BTRFS_CLEAR_OP_DISCARD);
 
 			trimmed += group_trimmed;
 			if (ret) {
@@ -11023,7 +11042,8 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
 	devices = &fs_info->fs_devices->alloc_list;
 	list_for_each_entry(device, devices, dev_alloc_list) {
 		ret = btrfs_trim_free_extents(device, range->minlen,
-					      &group_trimmed);
+					      &group_trimmed,
+					      BTRFS_CLEAR_OP_DISCARD);
 		if (ret)
 			break;
 
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index e5b569bebc73..be7bfb99df9a 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -3102,7 +3102,8 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster)
 static int do_trimming(struct btrfs_block_group_cache *block_group,
 		       u64 *total_trimmed, u64 start, u64 bytes,
 		       u64 reserved_start, u64 reserved_bytes,
-		       struct btrfs_trim_range *trim_entry)
+		       struct btrfs_trim_range *trim_entry,
+		       enum btrfs_clear_op_type clear)
 {
 	struct btrfs_space_info *space_info = block_group->space_info;
 	struct btrfs_fs_info *fs_info = block_group->fs_info;
@@ -3121,7 +3122,7 @@ static int do_trimming(struct btrfs_block_group_cache *block_group,
 	spin_unlock(&block_group->lock);
 	spin_unlock(&space_info->lock);
 
-	ret = btrfs_discard_extent(fs_info, start, bytes, &trimmed);
+	ret = btrfs_discard_extent(fs_info, start, bytes, &trimmed, clear);
 	if (!ret)
 		*total_trimmed += trimmed;
 
@@ -3145,7 +3146,8 @@ static int do_trimming(struct btrfs_block_group_cache *block_group,
 }
 
 static int trim_no_bitmap(struct btrfs_block_group_cache *block_group,
-			  u64 *total_trimmed, u64 start, u64 end, u64 minlen)
+			  u64 *total_trimmed, u64 start, u64 end, u64 minlen,
+			  enum btrfs_clear_op_type clear)
 {
 	struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
 	struct btrfs_free_space *entry;
@@ -3212,7 +3214,7 @@ static int trim_no_bitmap(struct btrfs_block_group_cache *block_group,
 		mutex_unlock(&ctl->cache_writeout_mutex);
 
 		ret = do_trimming(block_group, total_trimmed, start, bytes,
-				  extent_start, extent_bytes, &trim_entry);
+				extent_start, extent_bytes, &trim_entry, clear);
 		if (ret)
 			break;
 next:
@@ -3230,7 +3232,8 @@ static int trim_no_bitmap(struct btrfs_block_group_cache *block_group,
 }
 
 static int trim_bitmaps(struct btrfs_block_group_cache *block_group,
-			u64 *total_trimmed, u64 start, u64 end, u64 minlen)
+			u64 *total_trimmed, u64 start, u64 end, u64 minlen,
+			enum btrfs_clear_op_type clear)
 {
 	struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
 	struct btrfs_free_space *entry;
@@ -3287,7 +3290,7 @@ static int trim_bitmaps(struct btrfs_block_group_cache *block_group,
 		mutex_unlock(&ctl->cache_writeout_mutex);
 
 		ret = do_trimming(block_group, total_trimmed, start, bytes,
-				  start, bytes, &trim_entry);
+				  start, bytes, &trim_entry, clear);
 		if (ret)
 			break;
 next:
@@ -3355,7 +3358,8 @@ void btrfs_put_block_group_trimming(struct btrfs_block_group_cache *block_group)
 }
 
 int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
-			   u64 *trimmed, u64 start, u64 end, u64 minlen)
+			   u64 *trimmed, u64 start, u64 end, u64 minlen,
+			   enum btrfs_clear_op_type clear)
 {
 	int ret;
 
@@ -3369,11 +3373,11 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
 	btrfs_get_block_group_trimming(block_group);
 	spin_unlock(&block_group->lock);
 
-	ret = trim_no_bitmap(block_group, trimmed, start, end, minlen);
+	ret = trim_no_bitmap(block_group, trimmed, start, end, minlen, clear);
 	if (ret)
 		goto out;
 
-	ret = trim_bitmaps(block_group, trimmed, start, end, minlen);
+	ret = trim_bitmaps(block_group, trimmed, start, end, minlen, clear);
 out:
 	btrfs_put_block_group_trimming(block_group);
 	return ret;
diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h
index 15e30b93db0d..794a444c3f73 100644
--- a/fs/btrfs/free-space-cache.h
+++ b/fs/btrfs/free-space-cache.h
@@ -107,7 +107,8 @@ int btrfs_return_cluster_to_free_space(
 			       struct btrfs_block_group_cache *block_group,
 			       struct btrfs_free_cluster *cluster);
 int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
-			   u64 *trimmed, u64 start, u64 end, u64 minlen);
+			   u64 *trimmed, u64 start, u64 end, u64 minlen,
+			   enum btrfs_clear_op_type clear);
 
 /* Support functions for running our sanity tests */
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-- 
2.16.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/6] btrfs: add wrapper to switch clearing operation
  2018-04-20 14:21 [PATCH 0/6] Add ioctl to clear unused space David Sterba
  2018-04-20 14:21 ` [PATCH 1/6] btrfs: extend trim callchain to pass the operation type David Sterba
@ 2018-04-20 14:21 ` David Sterba
  2018-04-20 14:21 ` [PATCH 3/6] btrfs: add zeroing clear operation David Sterba
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Sterba @ 2018-04-20 14:21 UTC (permalink / raw)
  To: linux-btrfs; +Cc: David Sterba

Signed-off-by: David Sterba <dsterba@suse.com>
---
 fs/btrfs/extent-tree.c | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index ffdd3aba508c..b317f8ee42a9 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2034,6 +2034,18 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans,
 	return ret;
 }
 
+static int btrfs_issue_clear_op(struct block_device *bdev, u64 start, u64 size,
+		enum btrfs_clear_op_type clear)
+{
+	switch (clear) {
+	case BTRFS_CLEAR_OP_DISCARD:
+		return blkdev_issue_discard(bdev, start >> 9, size >> 9,
+				GFP_NOFS, 0);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 #define in_range(b, first, len)        ((b) >= (first) && (b) < (first) + (len))
 static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len,
 			       u64 *discarded_bytes,
@@ -2081,13 +2093,8 @@ static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len,
 			bytes_left = end - start;
 			continue;
 		}
-
 		if (size) {
-			if (clear == BTRFS_CLEAR_OP_DISCARD)
-				ret = blkdev_issue_discard(bdev, start >> 9,
-						size >> 9, GFP_NOFS, 0);
-			else
-				ret = -EOPNOTSUPP;
+			ret = btrfs_issue_clear_op(bdev, start, size, clear);
 			if (!ret)
 				*discarded_bytes += size;
 			else if (ret != -EOPNOTSUPP)
@@ -2103,11 +2110,7 @@ static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len,
 	}
 
 	if (bytes_left) {
-		if (clear == BTRFS_CLEAR_OP_DISCARD)
-			ret = blkdev_issue_discard(bdev, start >> 9,
-					bytes_left >> 9, GFP_NOFS, 0);
-		else
-			ret = -EOPNOTSUPP;
+		ret = btrfs_issue_clear_op(bdev, start, bytes_left, clear);
 		if (!ret)
 			*discarded_bytes += bytes_left;
 	}
-- 
2.16.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/6] btrfs: add zeroing clear operation
  2018-04-20 14:21 [PATCH 0/6] Add ioctl to clear unused space David Sterba
  2018-04-20 14:21 ` [PATCH 1/6] btrfs: extend trim callchain to pass the operation type David Sterba
  2018-04-20 14:21 ` [PATCH 2/6] btrfs: add wrapper to switch clearing operation David Sterba
@ 2018-04-20 14:21 ` David Sterba
  2018-04-20 14:21 ` [PATCH 4/6] btrfs: add new ioctl BTRFS_IOC_CLEAR_FREE David Sterba
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Sterba @ 2018-04-20 14:21 UTC (permalink / raw)
  To: linux-btrfs; +Cc: David Sterba

Signed-off-by: David Sterba <dsterba@suse.com>
---
 fs/btrfs/ctree.h       | 1 +
 fs/btrfs/extent-tree.c | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 7cde72683b8e..772cb4ccc5f7 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -679,6 +679,7 @@ struct btrfs_stripe_hash {
  */
 enum btrfs_clear_op_type {
 	BTRFS_CLEAR_OP_DISCARD = 0,
+	BTRFS_CLEAR_OP_ZERO,
 	BTRFS_NR_CLEAR_OP_TYPES,
 };
 
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index b317f8ee42a9..800aaf45e6bd 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2041,6 +2041,9 @@ static int btrfs_issue_clear_op(struct block_device *bdev, u64 start, u64 size,
 	case BTRFS_CLEAR_OP_DISCARD:
 		return blkdev_issue_discard(bdev, start >> 9, size >> 9,
 				GFP_NOFS, 0);
+	case BTRFS_CLEAR_OP_ZERO:
+		return blkdev_issue_zeroout(bdev, start >> 9, size >> 9,
+				GFP_NOFS, 0);
 	default:
 		return -EOPNOTSUPP;
 	}
-- 
2.16.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/6] btrfs: add new ioctl BTRFS_IOC_CLEAR_FREE
  2018-04-20 14:21 [PATCH 0/6] Add ioctl to clear unused space David Sterba
                   ` (2 preceding siblings ...)
  2018-04-20 14:21 ` [PATCH 3/6] btrfs: add zeroing clear operation David Sterba
@ 2018-04-20 14:21 ` David Sterba
  2018-04-20 14:21 ` [PATCH 5/6] btrfs: add discard secure to clear unused space David Sterba
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Sterba @ 2018-04-20 14:21 UTC (permalink / raw)
  To: linux-btrfs; +Cc: David Sterba

A new ioctl that will clear the free space (by writing zeros) given by
the user range. Similar to the TRIM ioctl.

We need a new ioctl for that because struct fstrim_range does not
provide any existing or reserved member for extensions. The new ioctl
also supports TRIM as the operation type.

Signed-off-by: David Sterba <dsterba@suse.com>
---
 fs/btrfs/ctree.h           | 11 ++---------
 fs/btrfs/extent-tree.c     | 48 ++++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/ioctl.c           | 42 ++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/btrfs.h | 20 +++++++++++++++++++
 4 files changed, 112 insertions(+), 9 deletions(-)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 772cb4ccc5f7..d8cc70a6bef7 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -674,15 +674,6 @@ struct btrfs_stripe_hash {
 	spinlock_t lock;
 };
 
-/*
- * Type of operation that will be used to clear unused blocks.
- */
-enum btrfs_clear_op_type {
-	BTRFS_CLEAR_OP_DISCARD = 0,
-	BTRFS_CLEAR_OP_ZERO,
-	BTRFS_NR_CLEAR_OP_TYPES,
-};
-
 /* used by the raid56 code to lock stripes for read/modify/write */
 struct btrfs_stripe_hash_table {
 	struct list_head stripe_cache;
@@ -2800,6 +2791,8 @@ int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,
 int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
 			 u64 num_bytes, u64 *actual_bytes,
 			 enum btrfs_clear_op_type clear);
+int btrfs_clear_free_space(struct btrfs_root *root,
+		struct btrfs_ioctl_clear_free_args *args);
 int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
 			    struct btrfs_fs_info *fs_info, u64 type);
 int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 800aaf45e6bd..21a24fff32dd 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -11061,6 +11061,54 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
 	return ret;
 }
 
+int btrfs_clear_free_space(struct btrfs_root *root,
+		struct btrfs_ioctl_clear_free_args *args)
+{
+	struct btrfs_fs_info *fs_info = root->fs_info;
+	struct btrfs_block_group_cache *cache = NULL;
+	u64 group_cleared;
+	u64 start;
+	u64 cleared = 0;
+	u64 end;
+	int ret = 0;
+
+	cache = btrfs_lookup_first_block_group(fs_info, args->start);
+
+	while (cache) {
+		if (cache->key.objectid >= (args->start + args->length)) {
+			btrfs_put_block_group(cache);
+			break;
+		}
+
+		start = max(args->start, cache->key.objectid);
+		end = min(args->start + args->length,
+				cache->key.objectid + cache->key.offset);
+
+		if (end - start >= args->minlen) {
+			if (!block_group_cache_done(cache)) {
+				ret = cache_block_group(cache, 0);
+				if (!ret)
+					wait_block_group_cache_done(cache);
+			}
+			ret = btrfs_trim_block_group(cache, &group_cleared,
+					start, end, args->minlen,
+					args->type);
+
+			if (ret) {
+				btrfs_put_block_group(cache);
+				break;
+			}
+			cleared += group_cleared;
+		}
+
+		cache = next_block_group(fs_info, cache);
+	}
+
+	args->length = cleared;
+
+	return ret;
+}
+
 /*
  * btrfs_{start,end}_write_no_snapshotting() are similar to
  * mnt_{want,drop}_write(), they are used to prevent some tasks from writing
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 9cc4fd25f83d..a56d4fb3ae82 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -5429,6 +5429,46 @@ static int _btrfs_ioctl_send(struct file *file, void __user *argp, bool compat)
 	return ret;
 }
 
+static int btrfs_ioctl_clear_free(struct file *file, void __user *arg)
+{
+	struct btrfs_fs_info *fs_info;
+	struct btrfs_ioctl_clear_free_args args;
+	u64 total_bytes;
+	int ret;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (copy_from_user(&args, arg, sizeof(args)))
+		return -EFAULT;
+
+	if (args.type >= BTRFS_NR_CLEAR_OP_TYPES)
+		return -EOPNOTSUPP;
+
+	ret = mnt_want_write_file(file);
+	if (ret)
+		return ret;
+
+	fs_info = btrfs_sb(file_inode(file)->i_sb);
+	total_bytes = btrfs_super_total_bytes(fs_info->super_copy);
+	if (args.start > total_bytes) {
+		ret = -EINVAL;
+		goto out_drop_write;
+	}
+
+	ret = btrfs_clear_free_space(fs_info->tree_root, &args);
+	if (ret < 0)
+		goto out_drop_write;
+
+	if (copy_to_user(arg, &args, sizeof(args)))
+		ret = -EFAULT;
+
+out_drop_write:
+	mnt_drop_write_file(file);
+
+	return 0;
+}
+
 long btrfs_ioctl(struct file *file, unsigned int
 		cmd, unsigned long arg)
 {
@@ -5565,6 +5605,8 @@ long btrfs_ioctl(struct file *file, unsigned int
 		return btrfs_ioctl_get_features(file, argp);
 	case BTRFS_IOC_SET_FEATURES:
 		return btrfs_ioctl_set_features(file, argp);
+	case BTRFS_IOC_CLEAR_FREE:
+		return btrfs_ioctl_clear_free(file, argp);
 	}
 
 	return -ENOTTY;
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index c8d99b9ca550..860f9df01614 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -737,6 +737,24 @@ enum btrfs_err_code {
 	BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS
 };
 
+/*
+ * Type of operation that will be used to clear unused blocks.
+ */
+enum btrfs_clear_op_type {
+	BTRFS_CLEAR_OP_DISCARD = 0,
+	BTRFS_CLEAR_OP_ZERO,
+	BTRFS_NR_CLEAR_OP_TYPES,
+};
+
+struct btrfs_ioctl_clear_free_args {
+	__u32 type;			/* in, btrfs_clear_free_op_type */
+	__u32 reserved1;		/* padding, must be zero */
+	__u64 start;			/* in */
+	__u64 length;			/* in, out */
+	__u64 minlen;			/* in */
+	__u64 reserved2[4];
+};
+
 #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
 				   struct btrfs_ioctl_vol_args)
 #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -843,5 +861,7 @@ enum btrfs_err_code {
 				   struct btrfs_ioctl_vol_args_v2)
 #define BTRFS_IOC_LOGICAL_INO_V2 _IOWR(BTRFS_IOCTL_MAGIC, 59, \
 					struct btrfs_ioctl_logical_ino_args)
+#define BTRFS_IOC_CLEAR_FREE _IOW(BTRFS_IOCTL_MAGIC, 90, \
+				struct btrfs_ioctl_clear_free_args)
 
 #endif /* _UAPI_LINUX_BTRFS_H */
-- 
2.16.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/6] btrfs: add discard secure to clear unused space
  2018-04-20 14:21 [PATCH 0/6] Add ioctl to clear unused space David Sterba
                   ` (3 preceding siblings ...)
  2018-04-20 14:21 ` [PATCH 4/6] btrfs: add new ioctl BTRFS_IOC_CLEAR_FREE David Sterba
@ 2018-04-20 14:21 ` David Sterba
  2018-04-20 14:21 ` [PATCH 6/6] btrfs: add more zeroout modes for clearing " David Sterba
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Sterba @ 2018-04-20 14:21 UTC (permalink / raw)
  To: linux-btrfs; +Cc: David Sterba

Signed-off-by: David Sterba <dsterba@suse.com>
---
 fs/btrfs/extent-tree.c     | 14 ++++++++++++--
 include/uapi/linux/btrfs.h |  1 +
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 21a24fff32dd..285bace8e2c6 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2037,10 +2037,15 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans,
 static int btrfs_issue_clear_op(struct block_device *bdev, u64 start, u64 size,
 		enum btrfs_clear_op_type clear)
 {
+	int flags = 0;
+
 	switch (clear) {
+	case BTRFS_CLEAR_OP_DISCARD_SECURE:
+		flags = BLKDEV_DISCARD_SECURE;
+		/* fall through */
 	case BTRFS_CLEAR_OP_DISCARD:
 		return blkdev_issue_discard(bdev, start >> 9, size >> 9,
-				GFP_NOFS, 0);
+				GFP_NOFS, flags);
 	case BTRFS_CLEAR_OP_ZERO:
 		return blkdev_issue_zeroout(bdev, start >> 9, size >> 9,
 				GFP_NOFS, 0);
@@ -2129,7 +2134,8 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
 	struct btrfs_bio *bbio = NULL;
 	int rw;
 
-	if (clear == BTRFS_CLEAR_OP_DISCARD)
+	if (clear == BTRFS_CLEAR_OP_DISCARD ||
+	    clear == BTRFS_CLEAR_OP_DISCARD_SECURE)
 		rw = BTRFS_MAP_DISCARD;
 	else
 		rw = BTRFS_MAP_WRITE;
@@ -2160,6 +2166,10 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
 			    !blk_queue_discard(req_q))
 				continue;
 
+			if (clear == BTRFS_CLEAR_OP_DISCARD_SECURE &&
+			    !blk_queue_secure_erase(req_q))
+				continue;
+
 			ret = btrfs_issue_discard(stripe->dev->bdev,
 						  stripe->physical,
 						  stripe->length,
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index 860f9df01614..1becbb241e53 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -743,6 +743,7 @@ enum btrfs_err_code {
 enum btrfs_clear_op_type {
 	BTRFS_CLEAR_OP_DISCARD = 0,
 	BTRFS_CLEAR_OP_ZERO,
+	BTRFS_CLEAR_OP_DISCARD_SECURE,
 	BTRFS_NR_CLEAR_OP_TYPES,
 };
 
-- 
2.16.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 6/6] btrfs: add more zeroout modes for clearing unused space
  2018-04-20 14:21 [PATCH 0/6] Add ioctl to clear unused space David Sterba
                   ` (4 preceding siblings ...)
  2018-04-20 14:21 ` [PATCH 5/6] btrfs: add discard secure to clear unused space David Sterba
@ 2018-04-20 14:21 ` David Sterba
  2018-04-20 14:49 ` [PATCH 0/6] Add ioctl to clear " Austin S. Hemmelgarn
  2018-06-07 12:17 ` David Sterba
  7 siblings, 0 replies; 9+ messages in thread
From: David Sterba @ 2018-04-20 14:21 UTC (permalink / raw)
  To: linux-btrfs; +Cc: David Sterba

Signed-off-by: David Sterba <dsterba@suse.com>
---
 fs/btrfs/extent-tree.c     | 12 +++++++++++-
 include/uapi/linux/btrfs.h |  5 +++++
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 285bace8e2c6..bd2ac5779998 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2046,9 +2046,19 @@ static int btrfs_issue_clear_op(struct block_device *bdev, u64 start, u64 size,
 	case BTRFS_CLEAR_OP_DISCARD:
 		return blkdev_issue_discard(bdev, start >> 9, size >> 9,
 				GFP_NOFS, flags);
+	case BTRFS_CLEAR_OP_ZERO_NOUNMAP:
+		flags = BLKDEV_ZERO_NOUNMAP;
+		goto zeroout;
+	case BTRFS_CLEAR_OP_ZERO_NOFALLBACK:
+		flags = BLKDEV_ZERO_NOFALLBACK;
+		goto zeroout;
+	case BTRFS_CLEAR_OP_ZERO_NOUNMAP_NOFALLBACK:
+		flags = BLKDEV_ZERO_NOUNMAP | BLKDEV_ZERO_NOFALLBACK;
+		/* fall through */
 	case BTRFS_CLEAR_OP_ZERO:
+zeroout:
 		return blkdev_issue_zeroout(bdev, start >> 9, size >> 9,
-				GFP_NOFS, 0);
+				GFP_NOFS, flags);
 	default:
 		return -EOPNOTSUPP;
 	}
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index 1becbb241e53..5d1f13045906 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -744,6 +744,11 @@ enum btrfs_clear_op_type {
 	BTRFS_CLEAR_OP_DISCARD = 0,
 	BTRFS_CLEAR_OP_ZERO,
 	BTRFS_CLEAR_OP_DISCARD_SECURE,
+
+	/* Fine tuning for clearing by zeros, see __blkdev_issue_zeroout */
+	BTRFS_CLEAR_OP_ZERO_NOUNMAP,
+	BTRFS_CLEAR_OP_ZERO_NOFALLBACK,
+	BTRFS_CLEAR_OP_ZERO_NOUNMAP_NOFALLBACK,
 	BTRFS_NR_CLEAR_OP_TYPES,
 };
 
-- 
2.16.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/6] Add ioctl to clear unused space
  2018-04-20 14:21 [PATCH 0/6] Add ioctl to clear unused space David Sterba
                   ` (5 preceding siblings ...)
  2018-04-20 14:21 ` [PATCH 6/6] btrfs: add more zeroout modes for clearing " David Sterba
@ 2018-04-20 14:49 ` Austin S. Hemmelgarn
  2018-06-07 12:17 ` David Sterba
  7 siblings, 0 replies; 9+ messages in thread
From: Austin S. Hemmelgarn @ 2018-04-20 14:49 UTC (permalink / raw)
  To: David Sterba, linux-btrfs

On 2018-04-20 10:21, David Sterba wrote:
> This patchset adds new ioctl similar to TRIM, that provides several
> other ways how to clear the unused space.  The changelogs are
> incomplete, for preview not for inclusion yet.
+1 for the idea.  This will be insanely useful for certain VM setups.
> 
> It compiles and has been tested lightly, the clearing modes depend on hw
> capabilities (secure discard, sector unmapping instead of zeros), so
> I've tested only zeroing and discard.
I don't have specific experience with blkdev_issue_zeroout, but I think 
the sector unmapping may be covered by the discard support.  When 
dealing with SCSI devices, discard operations get converted to the SCSI 
UNMAP command, which just based on the naming, sounds like what 
blkdev_issue_zeroout is issuing (at least, when dealing with SCSI 
devices).  Pretty much, the SCSI command works just like the ATA TRIM 
command does on ATA devices which zero data on discard (except it's 
SCSI, so it can pretty much always be queued, and has some other 
semantics around it that give it better performance than ATA TRIM).

Assuming that is the case, the unmapping support could be tested using 
the QEMU PV-SCSI driver (which supports the UNMAP command) with 
appropriate backing storage.  I can look at doing this testing myself, 
as I already use PV-SCSI for storage on all my QEMU VM's.
> 
> I personally think the zeroing has a usecase and the other modes were
> easy to add. Further extensions can be considered, eg. WRITE_SAME,
> overwriting with a randomly generated pattern, or some filesystem canary
> patterns that can be used to report unused block read as metadata.
Zeroing does have a use-case.  It's wonderfully useful for handling 
compaction of VM disks when using a virtual machine manager that doesn't 
support discard operations for this purpose.  I can also see the secure 
discard support being useful (though not necessarily the sector 
unmapping support for reasons mentioned above).
> 
> As this is modelled after the generic FITRIM ioctl, so this could be a
> new generic ioctl too. However, last time somebody wanted such ioctl,
> there was a pushback. I'll consider making a generic version and send it
> for comments to fsdevel eventually.
> 
> git://github.com/kdave/btrfs-devel dev/zero-free
> 
> 
> David Sterba (6):
>    btrfs: extend trim callchain to pass the operation type
>    btrfs: add wrapper to switch clearing operation
>    btrfs: add zeroing clear operation
>    btrfs: add new ioctl BTRFS_IOC_CLEAR_FREE
>    btrfs: add discard secure to clear unused space
>    btrfs: add more zeroout modes for clearing unused space
> 
>   fs/btrfs/ctree.h            |   5 +-
>   fs/btrfs/extent-tree.c      | 130 ++++++++++++++++++++++++++++++++++++++------
>   fs/btrfs/free-space-cache.c |  22 +++++---
>   fs/btrfs/free-space-cache.h |   3 +-
>   fs/btrfs/ioctl.c            |  42 ++++++++++++++
>   include/uapi/linux/btrfs.h  |  26 +++++++++
>   6 files changed, 199 insertions(+), 29 deletions(-)
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/6] Add ioctl to clear unused space
  2018-04-20 14:21 [PATCH 0/6] Add ioctl to clear unused space David Sterba
                   ` (6 preceding siblings ...)
  2018-04-20 14:49 ` [PATCH 0/6] Add ioctl to clear " Austin S. Hemmelgarn
@ 2018-06-07 12:17 ` David Sterba
  7 siblings, 0 replies; 9+ messages in thread
From: David Sterba @ 2018-06-07 12:17 UTC (permalink / raw)
  To: David Sterba; +Cc: linux-btrfs

On Fri, Apr 20, 2018 at 04:21:43PM +0200, David Sterba wrote:
> This patchset adds new ioctl similar to TRIM, that provides several
> other ways how to clear the unused space.  The changelogs are
> incomplete, for preview not for inclusion yet.
> 
> It compiles and has been tested lightly, the clearing modes depend on hw
> capabilities (secure discard, sector unmapping instead of zeros), so
> I've tested only zeroing and discard.
> 
> I personally think the zeroing has a usecase and the other modes were
> easy to add. Further extensions can be considered, eg. WRITE_SAME,
> overwriting with a randomly generated pattern, or some filesystem canary
> patterns that can be used to report unused block read as metadata.
> 
> As this is modelled after the generic FITRIM ioctl, so this could be a
> new generic ioctl too. However, last time somebody wanted such ioctl,
> there was a pushback. I'll consider making a generic version and send it
> for comments to fsdevel eventually.
> 
> git://github.com/kdave/btrfs-devel dev/zero-free
> 
> 
> David Sterba (6):
>   btrfs: extend trim callchain to pass the operation type
>   btrfs: add wrapper to switch clearing operation
>   btrfs: add zeroing clear operation
>   btrfs: add new ioctl BTRFS_IOC_CLEAR_FREE
>   btrfs: add discard secure to clear unused space
>   btrfs: add more zeroout modes for clearing unused space

For the record, this patchset has been shifted to 4.19 or later.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2018-06-07 12:20 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-20 14:21 [PATCH 0/6] Add ioctl to clear unused space David Sterba
2018-04-20 14:21 ` [PATCH 1/6] btrfs: extend trim callchain to pass the operation type David Sterba
2018-04-20 14:21 ` [PATCH 2/6] btrfs: add wrapper to switch clearing operation David Sterba
2018-04-20 14:21 ` [PATCH 3/6] btrfs: add zeroing clear operation David Sterba
2018-04-20 14:21 ` [PATCH 4/6] btrfs: add new ioctl BTRFS_IOC_CLEAR_FREE David Sterba
2018-04-20 14:21 ` [PATCH 5/6] btrfs: add discard secure to clear unused space David Sterba
2018-04-20 14:21 ` [PATCH 6/6] btrfs: add more zeroout modes for clearing " David Sterba
2018-04-20 14:49 ` [PATCH 0/6] Add ioctl to clear " Austin S. Hemmelgarn
2018-06-07 12:17 ` David Sterba

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.