diff options
-rw-r--r-- | fs/ocfs2/refcounttree.c | 2 | ||||
-rw-r--r-- | fs/read_write.c | 55 | ||||
-rw-r--r-- | fs/xfs/xfs_reflink.c | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 9 | ||||
-rw-r--r-- | mm/filemap.c | 69 |
5 files changed, 90 insertions, 47 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 7a5ee145c733..19e03936c5e1 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
@@ -4850,7 +4850,7 @@ int ocfs2_reflink_remap_range(struct file *file_in, | |||
4850 | (OCFS2_I(inode_out)->ip_flags & OCFS2_INODE_SYSTEM_FILE)) | 4850 | (OCFS2_I(inode_out)->ip_flags & OCFS2_INODE_SYSTEM_FILE)) |
4851 | goto out_unlock; | 4851 | goto out_unlock; |
4852 | 4852 | ||
4853 | ret = vfs_clone_file_prep_inodes(inode_in, pos_in, inode_out, pos_out, | 4853 | ret = vfs_clone_file_prep(file_in, pos_in, file_out, pos_out, |
4854 | &len, is_dedupe); | 4854 | &len, is_dedupe); |
4855 | if (ret <= 0) | 4855 | if (ret <= 0) |
4856 | goto out_unlock; | 4856 | goto out_unlock; |
diff --git a/fs/read_write.c b/fs/read_write.c index 260797b01851..d6e8e242a15f 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -1717,13 +1717,12 @@ static int clone_verify_area(struct file *file, loff_t pos, u64 len, bool write) | |||
1717 | * Returns: 0 for "nothing to clone", 1 for "something to clone", or | 1717 | * Returns: 0 for "nothing to clone", 1 for "something to clone", or |
1718 | * the usual negative error code. | 1718 | * the usual negative error code. |
1719 | */ | 1719 | */ |
1720 | int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in, | 1720 | int vfs_clone_file_prep(struct file *file_in, loff_t pos_in, |
1721 | struct inode *inode_out, loff_t pos_out, | 1721 | struct file *file_out, loff_t pos_out, |
1722 | u64 *len, bool is_dedupe) | 1722 | u64 *len, bool is_dedupe) |
1723 | { | 1723 | { |
1724 | loff_t bs = inode_out->i_sb->s_blocksize; | 1724 | struct inode *inode_in = file_inode(file_in); |
1725 | loff_t blen; | 1725 | struct inode *inode_out = file_inode(file_out); |
1726 | loff_t isize; | ||
1727 | bool same_inode = (inode_in == inode_out); | 1726 | bool same_inode = (inode_in == inode_out); |
1728 | int ret; | 1727 | int ret; |
1729 | 1728 | ||
@@ -1740,10 +1739,10 @@ int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in, | |||
1740 | if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode)) | 1739 | if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode)) |
1741 | return -EINVAL; | 1740 | return -EINVAL; |
1742 | 1741 | ||
1743 | isize = i_size_read(inode_in); | ||
1744 | |||
1745 | /* Zero length dedupe exits immediately; reflink goes to EOF. */ | 1742 | /* Zero length dedupe exits immediately; reflink goes to EOF. */ |
1746 | if (*len == 0) { | 1743 | if (*len == 0) { |
1744 | loff_t isize = i_size_read(inode_in); | ||
1745 | |||
1747 | if (is_dedupe || pos_in == isize) | 1746 | if (is_dedupe || pos_in == isize) |
1748 | return 0; | 1747 | return 0; |
1749 | if (pos_in > isize) | 1748 | if (pos_in > isize) |
@@ -1751,36 +1750,11 @@ int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in, | |||
1751 | *len = isize - pos_in; | 1750 | *len = isize - pos_in; |
1752 | } | 1751 | } |
1753 | 1752 | ||
1754 | /* Ensure offsets don't wrap and the input is inside i_size */ | 1753 | /* Check that we don't violate system file offset limits. */ |
1755 | if (pos_in + *len < pos_in || pos_out + *len < pos_out || | 1754 | ret = generic_remap_checks(file_in, pos_in, file_out, pos_out, len, |
1756 | pos_in + *len > isize) | 1755 | is_dedupe); |
1757 | return -EINVAL; | 1756 | if (ret) |
1758 | 1757 | return ret; | |
1759 | /* Don't allow dedupe past EOF in the dest file */ | ||
1760 | if (is_dedupe) { | ||
1761 | loff_t disize; | ||
1762 | |||
1763 | disize = i_size_read(inode_out); | ||
1764 | if (pos_out >= disize || pos_out + *len > disize) | ||
1765 | return -EINVAL; | ||
1766 | } | ||
1767 | |||
1768 | /* If we're linking to EOF, continue to the block boundary. */ | ||
1769 | if (pos_in + *len == isize) | ||
1770 | blen = ALIGN(isize, bs) - pos_in; | ||
1771 | else | ||
1772 | blen = *len; | ||
1773 | |||
1774 | /* Only reflink if we're aligned to block boundaries */ | ||
1775 | if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_in + blen, bs) || | ||
1776 | !IS_ALIGNED(pos_out, bs) || !IS_ALIGNED(pos_out + blen, bs)) | ||
1777 | return -EINVAL; | ||
1778 | |||
1779 | /* Don't allow overlapped reflink within the same file */ | ||
1780 | if (same_inode) { | ||
1781 | if (pos_out + blen > pos_in && pos_out < pos_in + blen) | ||
1782 | return -EINVAL; | ||
1783 | } | ||
1784 | 1758 | ||
1785 | /* Wait for the completion of any pending IOs on both files */ | 1759 | /* Wait for the completion of any pending IOs on both files */ |
1786 | inode_dio_wait(inode_in); | 1760 | inode_dio_wait(inode_in); |
@@ -1813,7 +1787,7 @@ int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in, | |||
1813 | 1787 | ||
1814 | return 1; | 1788 | return 1; |
1815 | } | 1789 | } |
1816 | EXPORT_SYMBOL(vfs_clone_file_prep_inodes); | 1790 | EXPORT_SYMBOL(vfs_clone_file_prep); |
1817 | 1791 | ||
1818 | int do_clone_file_range(struct file *file_in, loff_t pos_in, | 1792 | int do_clone_file_range(struct file *file_in, loff_t pos_in, |
1819 | struct file *file_out, loff_t pos_out, u64 len) | 1793 | struct file *file_out, loff_t pos_out, u64 len) |
@@ -1851,9 +1825,6 @@ int do_clone_file_range(struct file *file_in, loff_t pos_in, | |||
1851 | if (ret) | 1825 | if (ret) |
1852 | return ret; | 1826 | return ret; |
1853 | 1827 | ||
1854 | if (pos_in + len > i_size_read(inode_in)) | ||
1855 | return -EINVAL; | ||
1856 | |||
1857 | ret = file_in->f_op->clone_file_range(file_in, pos_in, | 1828 | ret = file_in->f_op->clone_file_range(file_in, pos_in, |
1858 | file_out, pos_out, len); | 1829 | file_out, pos_out, len); |
1859 | if (!ret) { | 1830 | if (!ret) { |
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 42ea7bab9144..281d5f53f2ec 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c | |||
@@ -1326,7 +1326,7 @@ xfs_reflink_remap_prep( | |||
1326 | if (IS_DAX(inode_in) || IS_DAX(inode_out)) | 1326 | if (IS_DAX(inode_in) || IS_DAX(inode_out)) |
1327 | goto out_unlock; | 1327 | goto out_unlock; |
1328 | 1328 | ||
1329 | ret = vfs_clone_file_prep_inodes(inode_in, pos_in, inode_out, pos_out, | 1329 | ret = vfs_clone_file_prep(file_in, pos_in, file_out, pos_out, |
1330 | len, is_dedupe); | 1330 | len, is_dedupe); |
1331 | if (ret <= 0) | 1331 | if (ret <= 0) |
1332 | goto out_unlock; | 1332 | goto out_unlock; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 897eae8faee1..ba93a6e7dac4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1825,9 +1825,9 @@ extern ssize_t vfs_readv(struct file *, const struct iovec __user *, | |||
1825 | unsigned long, loff_t *, rwf_t); | 1825 | unsigned long, loff_t *, rwf_t); |
1826 | extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct file *, | 1826 | extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct file *, |
1827 | loff_t, size_t, unsigned int); | 1827 | loff_t, size_t, unsigned int); |
1828 | extern int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in, | 1828 | extern int vfs_clone_file_prep(struct file *file_in, loff_t pos_in, |
1829 | struct inode *inode_out, loff_t pos_out, | 1829 | struct file *file_out, loff_t pos_out, |
1830 | u64 *len, bool is_dedupe); | 1830 | u64 *count, bool is_dedupe); |
1831 | extern int do_clone_file_range(struct file *file_in, loff_t pos_in, | 1831 | extern int do_clone_file_range(struct file *file_in, loff_t pos_in, |
1832 | struct file *file_out, loff_t pos_out, u64 len); | 1832 | struct file *file_out, loff_t pos_out, u64 len); |
1833 | extern int vfs_clone_file_range(struct file *file_in, loff_t pos_in, | 1833 | extern int vfs_clone_file_range(struct file *file_in, loff_t pos_in, |
@@ -2967,6 +2967,9 @@ extern int sb_min_blocksize(struct super_block *, int); | |||
2967 | extern int generic_file_mmap(struct file *, struct vm_area_struct *); | 2967 | extern int generic_file_mmap(struct file *, struct vm_area_struct *); |
2968 | extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *); | 2968 | extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *); |
2969 | extern ssize_t generic_write_checks(struct kiocb *, struct iov_iter *); | 2969 | extern ssize_t generic_write_checks(struct kiocb *, struct iov_iter *); |
2970 | extern int generic_remap_checks(struct file *file_in, loff_t pos_in, | ||
2971 | struct file *file_out, loff_t pos_out, | ||
2972 | uint64_t *count, bool is_dedupe); | ||
2970 | extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *); | 2973 | extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *); |
2971 | extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *); | 2974 | extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *); |
2972 | extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *); | 2975 | extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *); |
diff --git a/mm/filemap.c b/mm/filemap.c index 52517f28e6f4..47e6bfd45a91 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -2974,6 +2974,75 @@ inline ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from) | |||
2974 | } | 2974 | } |
2975 | EXPORT_SYMBOL(generic_write_checks); | 2975 | EXPORT_SYMBOL(generic_write_checks); |
2976 | 2976 | ||
2977 | /* | ||
2978 | * Performs necessary checks before doing a clone. | ||
2979 | * | ||
2980 | * Can adjust amount of bytes to clone. | ||
2981 | * Returns appropriate error code that caller should return or | ||
2982 | * zero in case the clone should be allowed. | ||
2983 | */ | ||
2984 | int generic_remap_checks(struct file *file_in, loff_t pos_in, | ||
2985 | struct file *file_out, loff_t pos_out, | ||
2986 | uint64_t *req_count, bool is_dedupe) | ||
2987 | { | ||
2988 | struct inode *inode_in = file_in->f_mapping->host; | ||
2989 | struct inode *inode_out = file_out->f_mapping->host; | ||
2990 | uint64_t count = *req_count; | ||
2991 | uint64_t bcount; | ||
2992 | loff_t size_in, size_out; | ||
2993 | loff_t bs = inode_out->i_sb->s_blocksize; | ||
2994 | |||
2995 | /* The start of both ranges must be aligned to an fs block. */ | ||
2996 | if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_out, bs)) | ||
2997 | return -EINVAL; | ||
2998 | |||
2999 | /* Ensure offsets don't wrap. */ | ||
3000 | if (pos_in + count < pos_in || pos_out + count < pos_out) | ||
3001 | return -EINVAL; | ||
3002 | |||
3003 | size_in = i_size_read(inode_in); | ||
3004 | size_out = i_size_read(inode_out); | ||
3005 | |||
3006 | /* Dedupe requires both ranges to be within EOF. */ | ||
3007 | if (is_dedupe && | ||
3008 | (pos_in >= size_in || pos_in + count > size_in || | ||
3009 | pos_out >= size_out || pos_out + count > size_out)) | ||
3010 | return -EINVAL; | ||
3011 | |||
3012 | /* Ensure the infile range is within the infile. */ | ||
3013 | if (pos_in >= size_in) | ||
3014 | return -EINVAL; | ||
3015 | count = min(count, size_in - (uint64_t)pos_in); | ||
3016 | |||
3017 | /* | ||
3018 | * If the user wanted us to link to the infile's EOF, round up to the | ||
3019 | * next block boundary for this check. | ||
3020 | * | ||
3021 | * Otherwise, make sure the count is also block-aligned, having | ||
3022 | * already confirmed the starting offsets' block alignment. | ||
3023 | */ | ||
3024 | if (pos_in + count == size_in) { | ||
3025 | bcount = ALIGN(size_in, bs) - pos_in; | ||
3026 | } else { | ||
3027 | if (!IS_ALIGNED(count, bs)) | ||
3028 | return -EINVAL; | ||
3029 | |||
3030 | bcount = count; | ||
3031 | } | ||
3032 | |||
3033 | /* Don't allow overlapped cloning within the same file. */ | ||
3034 | if (inode_in == inode_out && | ||
3035 | pos_out + bcount > pos_in && | ||
3036 | pos_out < pos_in + bcount) | ||
3037 | return -EINVAL; | ||
3038 | |||
3039 | /* For now we don't support changing the length. */ | ||
3040 | if (*req_count != count) | ||
3041 | return -EINVAL; | ||
3042 | |||
3043 | return 0; | ||
3044 | } | ||
3045 | |||
2977 | int pagecache_write_begin(struct file *file, struct address_space *mapping, | 3046 | int pagecache_write_begin(struct file *file, struct address_space *mapping, |
2978 | loff_t pos, unsigned len, unsigned flags, | 3047 | loff_t pos, unsigned len, unsigned flags, |
2979 | struct page **pagep, void **fsdata) | 3048 | struct page **pagep, void **fsdata) |