@@ -1593,7 +1593,8 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
cloned = file_in->f_op->remap_file_range(file_in, pos_in,
file_out, pos_out,
- min_t(loff_t, MAX_RW_COUNT, len), 0);
+ min_t(loff_t, MAX_RW_COUNT, len),
+ RFR_CAN_SHORTEN);
if (cloned >= 0) {
ret = cloned;
goto done;
@@ -1726,9 +1726,11 @@ struct block_device_operations;
*
* RFR_IDENTICAL_DATA: only remap if contents identical (i.e. deduplicate)
* RFR_TO_SRC_EOF: remap to the end of the source file
+ * RFR_CAN_SHORTEN: caller can handle a shortened request
*/
#define RFR_IDENTICAL_DATA (1 << 0)
#define RFR_TO_SRC_EOF (1 << 1)
+#define RFR_CAN_SHORTEN (1 << 2)
struct iov_iter;
@@ -3064,8 +3064,12 @@ int generic_remap_checks(struct file *file_in, loff_t pos_in,
if (pos_in + count == size_in) {
bcount = ALIGN(size_in, bs) - pos_in;
} else {
- if (!IS_ALIGNED(count, bs))
- return -EINVAL;
+ if (!IS_ALIGNED(count, bs)) {
+ if (remap_flags & RFR_CAN_SHORTEN)
+ count = ALIGN_DOWN(count, bs);
+ else
+ return -EINVAL;
+ }
bcount = count;
}
@@ -3076,10 +3080,14 @@ int generic_remap_checks(struct file *file_in, loff_t pos_in,
pos_out < pos_in + bcount)
return -EINVAL;
- /* For now we don't support changing the length. */
- if (*req_count != count)
+ /*
+ * We shortened the request but the caller can't deal with that, so
+ * bounce the request back to userspace.
+ */
+ if (*req_count != count && !(remap_flags & RFR_CAN_SHORTEN))
return -EINVAL;
+ *req_count = count;
return 0;
}