Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tmpfs: clone shmem_file_splice_read()

Copy __generic_file_splice_read() and generic_file_splice_read() from
fs/splice.c to shmem_file_splice_read() in mm/shmem.c. Make
page_cache_pipe_buf_ops and spd_release_page() accessible to it.

Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Jens Axboe <jaxboe@fusionio.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Hugh Dickins and committed by
Linus Torvalds
708e3508 2efaca92

+221 -3
+2 -2
fs/splice.c
··· 132 132 return err; 133 133 } 134 134 135 - static const struct pipe_buf_operations page_cache_pipe_buf_ops = { 135 + const struct pipe_buf_operations page_cache_pipe_buf_ops = { 136 136 .can_merge = 0, 137 137 .map = generic_pipe_buf_map, 138 138 .unmap = generic_pipe_buf_unmap, ··· 264 264 return ret; 265 265 } 266 266 267 - static void spd_release_page(struct splice_pipe_desc *spd, unsigned int i) 267 + void spd_release_page(struct splice_pipe_desc *spd, unsigned int i) 268 268 { 269 269 page_cache_release(spd->pages[i]); 270 270 }
+2
include/linux/splice.h
··· 88 88 extern int splice_grow_spd(struct pipe_inode_info *, struct splice_pipe_desc *); 89 89 extern void splice_shrink_spd(struct pipe_inode_info *, 90 90 struct splice_pipe_desc *); 91 + extern void spd_release_page(struct splice_pipe_desc *, unsigned int); 91 92 93 + extern const struct pipe_buf_operations page_cache_pipe_buf_ops; 92 94 #endif
+217 -1
mm/shmem.c
··· 51 51 #include <linux/shmem_fs.h> 52 52 #include <linux/writeback.h> 53 53 #include <linux/blkdev.h> 54 + #include <linux/splice.h> 54 55 #include <linux/security.h> 55 56 #include <linux/swapops.h> 56 57 #include <linux/mempolicy.h> ··· 1845 1844 return retval; 1846 1845 } 1847 1846 1847 + static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos, 1848 + struct pipe_inode_info *pipe, size_t len, 1849 + unsigned int flags) 1850 + { 1851 + struct address_space *mapping = in->f_mapping; 1852 + unsigned int loff, nr_pages, req_pages; 1853 + struct page *pages[PIPE_DEF_BUFFERS]; 1854 + struct partial_page partial[PIPE_DEF_BUFFERS]; 1855 + struct page *page; 1856 + pgoff_t index, end_index; 1857 + loff_t isize, left; 1858 + int error, page_nr; 1859 + struct splice_pipe_desc spd = { 1860 + .pages = pages, 1861 + .partial = partial, 1862 + .flags = flags, 1863 + .ops = &page_cache_pipe_buf_ops, 1864 + .spd_release = spd_release_page, 1865 + }; 1866 + 1867 + isize = i_size_read(in->f_mapping->host); 1868 + if (unlikely(*ppos >= isize)) 1869 + return 0; 1870 + 1871 + left = isize - *ppos; 1872 + if (unlikely(left < len)) 1873 + len = left; 1874 + 1875 + if (splice_grow_spd(pipe, &spd)) 1876 + return -ENOMEM; 1877 + 1878 + index = *ppos >> PAGE_CACHE_SHIFT; 1879 + loff = *ppos & ~PAGE_CACHE_MASK; 1880 + req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; 1881 + nr_pages = min(req_pages, pipe->buffers); 1882 + 1883 + /* 1884 + * Lookup the (hopefully) full range of pages we need. 1885 + */ 1886 + spd.nr_pages = find_get_pages_contig(mapping, index, 1887 + nr_pages, spd.pages); 1888 + index += spd.nr_pages; 1889 + 1890 + /* 1891 + * If find_get_pages_contig() returned fewer pages than we needed, 1892 + * readahead/allocate the rest and fill in the holes. 1893 + */ 1894 + if (spd.nr_pages < nr_pages) 1895 + page_cache_sync_readahead(mapping, &in->f_ra, in, 1896 + index, req_pages - spd.nr_pages); 1897 + 1898 + error = 0; 1899 + while (spd.nr_pages < nr_pages) { 1900 + /* 1901 + * Page could be there, find_get_pages_contig() breaks on 1902 + * the first hole. 1903 + */ 1904 + page = find_get_page(mapping, index); 1905 + if (!page) { 1906 + /* 1907 + * page didn't exist, allocate one. 1908 + */ 1909 + page = page_cache_alloc_cold(mapping); 1910 + if (!page) 1911 + break; 1912 + 1913 + error = add_to_page_cache_lru(page, mapping, index, 1914 + GFP_KERNEL); 1915 + if (unlikely(error)) { 1916 + page_cache_release(page); 1917 + if (error == -EEXIST) 1918 + continue; 1919 + break; 1920 + } 1921 + /* 1922 + * add_to_page_cache() locks the page, unlock it 1923 + * to avoid convoluting the logic below even more. 1924 + */ 1925 + unlock_page(page); 1926 + } 1927 + 1928 + spd.pages[spd.nr_pages++] = page; 1929 + index++; 1930 + } 1931 + 1932 + /* 1933 + * Now loop over the map and see if we need to start IO on any 1934 + * pages, fill in the partial map, etc. 1935 + */ 1936 + index = *ppos >> PAGE_CACHE_SHIFT; 1937 + nr_pages = spd.nr_pages; 1938 + spd.nr_pages = 0; 1939 + for (page_nr = 0; page_nr < nr_pages; page_nr++) { 1940 + unsigned int this_len; 1941 + 1942 + if (!len) 1943 + break; 1944 + 1945 + /* 1946 + * this_len is the max we'll use from this page 1947 + */ 1948 + this_len = min_t(unsigned long, len, PAGE_CACHE_SIZE - loff); 1949 + page = spd.pages[page_nr]; 1950 + 1951 + if (PageReadahead(page)) 1952 + page_cache_async_readahead(mapping, &in->f_ra, in, 1953 + page, index, req_pages - page_nr); 1954 + 1955 + /* 1956 + * If the page isn't uptodate, we may need to start io on it 1957 + */ 1958 + if (!PageUptodate(page)) { 1959 + lock_page(page); 1960 + 1961 + /* 1962 + * Page was truncated, or invalidated by the 1963 + * filesystem. Redo the find/create, but this time the 1964 + * page is kept locked, so there's no chance of another 1965 + * race with truncate/invalidate. 1966 + */ 1967 + if (!page->mapping) { 1968 + unlock_page(page); 1969 + page = find_or_create_page(mapping, index, 1970 + mapping_gfp_mask(mapping)); 1971 + 1972 + if (!page) { 1973 + error = -ENOMEM; 1974 + break; 1975 + } 1976 + page_cache_release(spd.pages[page_nr]); 1977 + spd.pages[page_nr] = page; 1978 + } 1979 + /* 1980 + * page was already under io and is now done, great 1981 + */ 1982 + if (PageUptodate(page)) { 1983 + unlock_page(page); 1984 + goto fill_it; 1985 + } 1986 + 1987 + /* 1988 + * need to read in the page 1989 + */ 1990 + error = mapping->a_ops->readpage(in, page); 1991 + if (unlikely(error)) { 1992 + /* 1993 + * We really should re-lookup the page here, 1994 + * but it complicates things a lot. Instead 1995 + * lets just do what we already stored, and 1996 + * we'll get it the next time we are called. 1997 + */ 1998 + if (error == AOP_TRUNCATED_PAGE) 1999 + error = 0; 2000 + 2001 + break; 2002 + } 2003 + } 2004 + fill_it: 2005 + /* 2006 + * i_size must be checked after PageUptodate. 2007 + */ 2008 + isize = i_size_read(mapping->host); 2009 + end_index = (isize - 1) >> PAGE_CACHE_SHIFT; 2010 + if (unlikely(!isize || index > end_index)) 2011 + break; 2012 + 2013 + /* 2014 + * if this is the last page, see if we need to shrink 2015 + * the length and stop 2016 + */ 2017 + if (end_index == index) { 2018 + unsigned int plen; 2019 + 2020 + /* 2021 + * max good bytes in this page 2022 + */ 2023 + plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1; 2024 + if (plen <= loff) 2025 + break; 2026 + 2027 + /* 2028 + * force quit after adding this page 2029 + */ 2030 + this_len = min(this_len, plen - loff); 2031 + len = this_len; 2032 + } 2033 + 2034 + spd.partial[page_nr].offset = loff; 2035 + spd.partial[page_nr].len = this_len; 2036 + len -= this_len; 2037 + loff = 0; 2038 + spd.nr_pages++; 2039 + index++; 2040 + } 2041 + 2042 + /* 2043 + * Release any pages at the end, if we quit early. 'page_nr' is how far 2044 + * we got, 'nr_pages' is how many pages are in the map. 2045 + */ 2046 + while (page_nr < nr_pages) 2047 + page_cache_release(spd.pages[page_nr++]); 2048 + in->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; 2049 + 2050 + if (spd.nr_pages) 2051 + error = splice_to_pipe(pipe, &spd); 2052 + 2053 + splice_shrink_spd(pipe, &spd); 2054 + 2055 + if (error > 0) { 2056 + *ppos += error; 2057 + file_accessed(in); 2058 + } 2059 + return error; 2060 + } 2061 + 1848 2062 static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf) 1849 2063 { 1850 2064 struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb); ··· 2915 2699 .aio_read = shmem_file_aio_read, 2916 2700 .aio_write = generic_file_aio_write, 2917 2701 .fsync = noop_fsync, 2918 - .splice_read = generic_file_splice_read, 2702 + .splice_read = shmem_file_splice_read, 2919 2703 .splice_write = generic_file_splice_write, 2920 2704 #endif 2921 2705 };