summaryrefslogtreecommitdiffstats
path: root/fs/read_write.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/read_write.c')
-rw-r--r--fs/read_write.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/fs/read_write.c b/fs/read_write.c
index 2456da3f8a41..0f0a6efdd502 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -1708,6 +1708,34 @@ static int clone_verify_area(struct file *file, loff_t pos, u64 len, bool write)
1708 1708
1709 return security_file_permission(file, write ? MAY_WRITE : MAY_READ); 1709 return security_file_permission(file, write ? MAY_WRITE : MAY_READ);
1710} 1710}
1711/*
1712 * Ensure that we don't remap a partial EOF block in the middle of something
1713 * else. Assume that the offsets have already been checked for block
1714 * alignment.
1715 *
1716 * For deduplication we always scale down to the previous block because we
1717 * can't meaningfully compare post-EOF contents.
1718 *
1719 * For clone we only link a partial EOF block above the destination file's EOF.
1720 */
1721static int generic_remap_check_len(struct inode *inode_in,
1722 struct inode *inode_out,
1723 loff_t pos_out,
1724 u64 *len,
1725 bool is_dedupe)
1726{
1727 u64 blkmask = i_blocksize(inode_in) - 1;
1728
1729 if ((*len & blkmask) == 0)
1730 return 0;
1731
1732 if (is_dedupe)
1733 *len &= ~blkmask;
1734 else if (pos_out + *len < i_size_read(inode_out))
1735 return -EINVAL;
1736
1737 return 0;
1738}
1711 1739
1712/* 1740/*
1713 * Check that the two inodes are eligible for cloning, the ranges make 1741 * Check that the two inodes are eligible for cloning, the ranges make
@@ -1787,6 +1815,11 @@ int vfs_clone_file_prep(struct file *file_in, loff_t pos_in,
1787 return -EBADE; 1815 return -EBADE;
1788 } 1816 }
1789 1817
1818 ret = generic_remap_check_len(inode_in, inode_out, pos_out, len,
1819 is_dedupe);
1820 if (ret)
1821 return ret;
1822
1790 return 1; 1823 return 1;
1791} 1824}
1792EXPORT_SYMBOL(vfs_clone_file_prep); 1825EXPORT_SYMBOL(vfs_clone_file_prep);