@@ -1723,6 +1723,7 @@ int vfs_clone_file_prep(struct file *file_in, loff_t pos_in,
{
struct inode *inode_in = file_inode(file_in);
struct inode *inode_out = file_inode(file_out);
+ u64 blkmask = i_blocksize(inode_in) - 1;
bool same_inode = (inode_in == inode_out);
int ret;
@@ -1785,6 +1786,22 @@ int vfs_clone_file_prep(struct file *file_in, loff_t pos_in,
return -EBADE;
}
+ /* Are we doing a partial EOF block remapping of some kind? */
+ if (*len & blkmask) {
+ /*
+ * If the dedupe data matches, chop off the partial EOF block
+ * from the source file so we don't try to dedupe the partial
+ * EOF block.
+ *
+ * If the user is attempting to remap a partial EOF block and
+ * it's inside the destination EOF then reject it.
+ */
+ if (is_dedupe)
+ *len &= ~blkmask;
+ else if (pos_out + *len < i_size_read(inode_out))
+ return -EINVAL;
+ }
+
return 1;
}
EXPORT_SYMBOL(vfs_clone_file_prep);