diff options
-rw-r--r-- | fs/read_write.c | 187 | ||||
-rw-r--r-- | include/linux/fs.h | 3 |
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 | */ | ||
1759 | static 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 | */ | ||
1778 | static 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 | |||
1842 | out_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 | } |
1924 | EXPORT_SYMBOL(vfs_clone_file_range); | 2015 | EXPORT_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 | */ | ||
1930 | static 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 | */ | ||
1953 | int 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 | |||
2017 | out_error: | ||
2018 | return error; | ||
2019 | } | ||
2020 | EXPORT_SYMBOL(vfs_dedupe_file_range_compare); | ||
2021 | |||
2022 | loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, | 2017 | loff_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, | |||
1853 | extern loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in, | 1853 | extern 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); |
1856 | extern 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); | ||
1859 | extern int vfs_dedupe_file_range(struct file *file, | 1856 | extern int vfs_dedupe_file_range(struct file *file, |
1860 | struct file_dedupe_range *same); | 1857 | struct file_dedupe_range *same); |
1861 | extern loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, | 1858 | extern loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, |