[PATCH v2] vfs: add FILE_DEDUPE_RANGE_REPORT_PROGRESS flag to FIDEDUPERANGE

Matthias Goergens <[email protected]>
Newsgroups gmane.linux.file-systems,gmane.linux.kernel
Message-ID <[email protected]>
FIDEDUPERANGE reports the requested length in bytes_deduped even when
the filesystem shortens a destination range and deduplicates fewer
bytes.  This predates the VFS hoisting of the ioctl (the btrfs ioctl
behaved the same way), and changing the default would change an ABI
that deployed consumers such as duperemove depend on: they advance
their offsets by bytes_deduped and expect the historical semantics.

Add a flag to opt into the truthful behaviour: with
FILE_DEDUPE_RANGE_REPORT_PROGRESS set, bytes_deduped reports the bytes
actually deduplicated, and a non-zero request shortened to zero fails
per destination with -EINVAL instead of reporting success with no
progress.  Unknown flag bits are rejected.

The flag leaves every existing caller's behaviour unchanged and lets
new callers request accurate progress reporting.

Suggested-by: Darrick J. Wong <[email protected]>
Link: https://lore.kernel.org/linux-fsdevel/[email protected]/
Signed-off-by: Matthias Goergens <[email protected]>
---
 fs/remap_range.c        | 7 ++++++-
 include/uapi/linux/fs.h | 4 +++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/fs/remap_range.c b/fs/remap_range.c
index 26afbbbfb10c2..16192ec19bb6d 100644
--- a/fs/remap_range.c
+++ b/fs/remap_range.c
@@ -503,7 +503,7 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
 	if (!(file->f_mode & FMODE_READ))
 		return -EINVAL;
 
-	if (same->reserved1 || same->reserved2)
+	if (same->reserved1 || (same->flags & ~FILE_DEDUPE_RANGE_REPORT_PROGRESS))
 		return -EINVAL;
 
 	off = same->src_offset;
@@ -555,6 +555,11 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
 			info->status = FILE_DEDUPE_RANGE_DIFFERS;
 		else if (deduped < 0)
 			info->status = deduped;
+		else if ((same->flags & FILE_DEDUPE_RANGE_REPORT_PROGRESS) &&
+			 !deduped && len)
+			info->status = -EINVAL;
+		else if (same->flags & FILE_DEDUPE_RANGE_REPORT_PROGRESS)
+			info->bytes_deduped = deduped;
 		else
 			info->bytes_deduped = len;
 
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index bd87262f2e349..abee40359bfd5 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -179,12 +179,14 @@ struct file_dedupe_range_info {
 };
 
 /* from struct btrfs_ioctl_file_extent_same_args */
+#define FILE_DEDUPE_RANGE_REPORT_PROGRESS 0x1
+
 struct file_dedupe_range {
 	__u64 src_offset;	/* in - start of extent in source */
 	__u64 src_length;	/* in - length of extent */
 	__u16 dest_count;	/* in - total elements in info array */
 	__u16 reserved1;	/* must be zero */
-	__u32 reserved2;	/* must be zero */
+	__u32 flags;		/* FILE_DEDUPE_RANGE_* flags; was reserved2 */
 	struct file_dedupe_range_info info[];
 };
 
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.