summaryrefslogtreecommitdiff
path: root/include/uapi
diff options
context:
space:
mode:
authorMatthias Goergens <matthias.goergens@gmail.com>2026-09-26 12:38:36 +0800
committerChristian Brauner <brauner@kernel.org>2026-11-03 15:42:19 +0100
commitcffe56e6a818f2b2d50fc8564b6398f8308ae9e8 (patch)
tree9089e15571fab27ba26cae052ac744f8e1bac8bf /include/uapi
parent6628e7d4c6b25c8d18f1345e3a20d21829aae7e4 (diff)
downloadlinux-next-cffe56e6a818f2b2d50fc8564b6398f8308ae9e8.tar.gz
linux-next-cffe56e6a818f2b2d50fc8564b6398f8308ae9e8.zip
vfs: add FILE_DEDUPE_RANGE_REPORT_PROGRESS flag to FIDEDUPERANGE
Deduplication tools such as duperemove, bees and rmlint advance their file offsets by the bytes_deduped the kernel returns for each FIDEDUPERANGE call. vfs_dedupe_file_range() passes REMAP_FILE_CAN_SHORTEN, so generic_remap_checks() may round the length down to a block multiple, but the ioctl still reports the requested length in bytes_deduped. The caller cannot tell that the tail of its request was left alone: rmlint 2.10.3 on btrfs (4 KiB blocks) deduping a 100000-byte file against a 250000-byte file with the same prefix is told bytes_deduped=100000 with status SAME while only 98304 bytes were actually shared; its loop ends and it reports the pair fully deduplicated. duperemove and bees advance the same way, and jdupes advances by its own requested length without reading the field; all of them skip such a tail. Add FILE_DEDUPE_RANGE_REPORT_PROGRESS for file_dedupe_range.flags: with it, bytes_deduped is the length the filesystem actually deduplicated when status is FILE_DEDUPE_RANGE_SAME, and 0 on FILE_DEDUPE_RANGE_DIFFERS or error. Callers advance by it as today, but must treat 0 as "stop or subdivide", not retry unchanged. One cause of SAME with 0 is a sub-block request that does not end at both files' EOF, which the generic range preparation shortens to nothing. On DIFFERS there is no sound progress or mismatch offset to report, so 0 leaves subdividing to the caller, as rmlint already does. The default cannot change: commit 4a57a8400075 ("vf/remap: return the amount of bytes actually deduplicated") did exactly that and was reverted the next day; among deployed callers, duperemove re-queues a request while its status is 0 and would re-issue the same sub-block request forever. Without the flag nothing changes. Suggested-by: Darrick J. Wong <djwong@kernel.org> Link: https://lore.kernel.org/linux-fsdevel/20260805071414.3414870-1-matthias.goergens@gmail.com/ Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com> Link: https://patch.msgid.link/20260926043836.3301898-3-matthias.goergens@gmail.com Reviewed-by: Amir Goldstein <amir73il@gmail.com> Reviewed-by: "Darrick J. Wong" <djwong@kernel.org> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Diffstat (limited to 'include/uapi')
-rw-r--r--include/uapi/linux/fs.h11
1 files changed, 10 insertions, 1 deletions
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index a46c33692aa2..a13c7b32a1bd 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -178,13 +178,22 @@ struct file_dedupe_range_info {
__u32 reserved; /* must be zero */
};
+/* flags for struct file_dedupe_range */
+/*
+ * Without this flag, bytes_deduped is the requested length on success,
+ * even if the filesystem deduplicated fewer bytes (e.g. after shortening
+ * the request to a block boundary). With this flag, bytes_deduped is
+ * the number of bytes actually deduplicated.
+ */
+#define FILE_DEDUPE_RANGE_REPORT_PROGRESS (1U << 0)
+
/* from struct btrfs_ioctl_file_extent_same_args */
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; /* in - FILE_DEDUPE_RANGE_* flags */
struct file_dedupe_range_info info[];
};