[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