aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/read_write.c187
-rw-r--r--include/linux/fs.h3
2 files changed, 91 insertions, 99 deletions
diff --git a/fs/read_write.c b/fs/read_write.c
index c0bcc1a20650..e4d295d0d236 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -1753,6 +1753,97 @@ static int generic_remap_check_len(struct inode *inode_in,
1753} 1753}
1754 1754
1755/* 1755/*
1756 * Read a page's worth of file data into the page cache. Return the page
1757 * locked.
1758 */
1759static struct page *vfs_dedupe_get_page(struct inode *inode, loff_t offset)
1760{
1761 struct page *page;
1762
1763 page = read_mapping_page(inode->i_mapping, offset >> PAGE_SHIFT, NULL);
1764 if (IS_ERR(page))
1765 return page;
1766 if (!PageUptodate(page)) {
1767 put_page(page);
1768 return ERR_PTR(-EIO);
1769 }
1770 lock_page(page);
1771 return page;
1772}
1773
1774/*
1775 * Compare extents of two files to see if they are the same.
1776 * Caller must have locked both inodes to prevent write races.
1777 */
1778static int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
1779 struct inode *dest, loff_t destoff,
1780 loff_t len, bool *is_same)
1781{
1782 loff_t src_poff;
1783 loff_t dest_poff;
1784 void *src_addr;
1785 void *dest_addr;
1786 struct page *src_page;
1787 struct page *dest_page;
1788 loff_t cmp_len;
1789 bool same;
1790 int error;
1791
1792 error = -EINVAL;
1793 same = true;
1794 while (len) {
1795 src_poff = srcoff & (PAGE_SIZE - 1);
1796 dest_poff = destoff & (PAGE_SIZE - 1);
1797 cmp_len = min(PAGE_SIZE - src_poff,
1798 PAGE_SIZE - dest_poff);
1799 cmp_len = min(cmp_len, len);
1800 if (cmp_len <= 0)
1801 goto out_error;
1802
1803 src_page = vfs_dedupe_get_page(src, srcoff);
1804 if (IS_ERR(src_page)) {
1805 error = PTR_ERR(src_page);
1806 goto out_error;
1807 }
1808 dest_page = vfs_dedupe_get_page(dest, destoff);
1809 if (IS_ERR(dest_page)) {
1810 error = PTR_ERR(dest_page);
1811 unlock_page(src_page);
1812 put_page(src_page);
1813 goto out_error;
1814 }
1815 src_addr = kmap_atomic(src_page);
1816 dest_addr = kmap_atomic(dest_page);
1817
1818 flush_dcache_page(src_page);
1819 flush_dcache_page(dest_page);
1820
1821 if (memcmp(src_addr + src_poff, dest_addr + dest_poff, cmp_len))
1822 same = false;
1823
1824 kunmap_atomic(dest_addr);
1825 kunmap_atomic(src_addr);
1826 unlock_page(dest_page);
1827 unlock_page(src_page);
1828 put_page(dest_page);
1829 put_page(src_page);
1830
1831 if (!same)
1832 break;
1833
1834 srcoff += cmp_len;
1835 destoff += cmp_len;
1836 len -= cmp_len;
1837 }
1838
1839 *is_same = same;
1840 return 0;
1841
1842out_error:
1843 return error;
1844}
1845
1846/*
1756 * Check that the two inodes are eligible for cloning, the ranges make 1847 * Check that the two inodes are eligible for cloning, the ranges make
1757 * sense, and then flush all dirty data. Caller must ensure that the 1848 * sense, and then flush all dirty data. Caller must ensure that the
1758 * inodes have been locked against any other modifications. 1849 * inodes have been locked against any other modifications.
@@ -1923,102 +2014,6 @@ loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in,
1923} 2014}
1924EXPORT_SYMBOL(vfs_clone_file_range); 2015EXPORT_SYMBOL(vfs_clone_file_range);
1925 2016
1926/*
1927 * Read a page's worth of file data into the page cache. Return the page
1928 * locked.
1929 */
1930static struct page *vfs_dedupe_get_page(struct inode *inode, loff_t offset)
1931{
1932 struct address_space *mapping;
1933 struct page *page;
1934 pgoff_t n;
1935
1936 n = offset >> PAGE_SHIFT;
1937 mapping = inode->i_mapping;
1938 page = read_mapping_page(mapping, n, NULL);
1939 if (IS_ERR(page))
1940 return page;
1941 if (!PageUptodate(page)) {
1942 put_page(page);
1943 return ERR_PTR(-EIO);
1944 }
1945 lock_page(page);
1946 return page;
1947}
1948
1949/*
1950 * Compare extents of two files to see if they are the same.
1951 * Caller must have locked both inodes to prevent write races.
1952 */
1953int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
1954 struct inode *dest, loff_t destoff,
1955 loff_t len, bool *is_same)
1956{
1957 loff_t src_poff;
1958 loff_t dest_poff;
1959 void *src_addr;
1960 void *dest_addr;
1961 struct page *src_page;
1962 struct page *dest_page;
1963 loff_t cmp_len;
1964 bool same;
1965 int error;
1966
1967 error = -EINVAL;
1968 same = true;
1969 while (len) {
1970 src_poff = srcoff & (PAGE_SIZE - 1);
1971 dest_poff = destoff & (PAGE_SIZE - 1);
1972 cmp_len = min(PAGE_SIZE - src_poff,
1973 PAGE_SIZE - dest_poff);
1974 cmp_len = min(cmp_len, len);
1975 if (cmp_len <= 0)
1976 goto out_error;
1977
1978 src_page = vfs_dedupe_get_page(src, srcoff);
1979 if (IS_ERR(src_page)) {
1980 error = PTR_ERR(src_page);
1981 goto out_error;
1982 }
1983 dest_page = vfs_dedupe_get_page(dest, destoff);
1984 if (IS_ERR(dest_page)) {
1985 error = PTR_ERR(dest_page);
1986 unlock_page(src_page);
1987 put_page(src_page);
1988 goto out_error;
1989 }
1990 src_addr = kmap_atomic(src_page);
1991 dest_addr = kmap_atomic(dest_page);
1992
1993 flush_dcache_page(src_page);
1994 flush_dcache_page(dest_page);
1995
1996 if (memcmp(src_addr + src_poff, dest_addr + dest_poff, cmp_len))
1997 same = false;
1998
1999 kunmap_atomic(dest_addr);
2000 kunmap_atomic(src_addr);
2001 unlock_page(dest_page);
2002 unlock_page(src_page);
2003 put_page(dest_page);
2004 put_page(src_page);
2005
2006 if (!same)
2007 break;
2008
2009 srcoff += cmp_len;
2010 destoff += cmp_len;
2011 len -= cmp_len;
2012 }
2013
2014 *is_same = same;
2015 return 0;
2016
2017out_error:
2018 return error;
2019}
2020EXPORT_SYMBOL(vfs_dedupe_file_range_compare);
2021
2022loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, 2017loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
2023 struct file *dst_file, loff_t dst_pos, 2018 struct file *dst_file, loff_t dst_pos,
2024 loff_t len, unsigned int remap_flags) 2019 loff_t len, unsigned int remap_flags)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 34c22d695011..346036a84f18 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1853,9 +1853,6 @@ extern loff_t do_clone_file_range(struct file *file_in, loff_t pos_in,
1853extern loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in, 1853extern loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in,
1854 struct file *file_out, loff_t pos_out, 1854 struct file *file_out, loff_t pos_out,
1855 loff_t len, unsigned int remap_flags); 1855 loff_t len, unsigned int remap_flags);
1856extern int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
1857 struct inode *dest, loff_t destoff,
1858 loff_t len, bool *is_same);
1859extern int vfs_dedupe_file_range(struct file *file, 1856extern int vfs_dedupe_file_range(struct file *file,
1860 struct file_dedupe_range *same); 1857 struct file_dedupe_range *same);
1861extern loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, 1858extern loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,