diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 35 |
1 files changed, 18 insertions, 17 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 4bf7d1ab6c2a..f74d05201862 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1838,16 +1838,15 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, | |||
1838 | size_t count, ssize_t written) | 1838 | size_t count, ssize_t written) |
1839 | { | 1839 | { |
1840 | struct file *file = iocb->ki_filp; | 1840 | struct file *file = iocb->ki_filp; |
1841 | struct address_space * mapping = file->f_mapping; | 1841 | struct address_space *mapping = file->f_mapping; |
1842 | const struct address_space_operations *a_ops = mapping->a_ops; | 1842 | const struct address_space_operations *a_ops = mapping->a_ops; |
1843 | struct inode *inode = mapping->host; | 1843 | struct inode *inode = mapping->host; |
1844 | long status = 0; | 1844 | long status = 0; |
1845 | struct page *page; | 1845 | struct page *page; |
1846 | struct page *cached_page = NULL; | 1846 | struct page *cached_page = NULL; |
1847 | size_t bytes; | ||
1848 | struct pagevec lru_pvec; | 1847 | struct pagevec lru_pvec; |
1849 | const struct iovec *cur_iov = iov; /* current iovec */ | 1848 | const struct iovec *cur_iov = iov; /* current iovec */ |
1850 | size_t iov_base = 0; /* offset in the current iovec */ | 1849 | size_t iov_offset = 0; /* offset in the current iovec */ |
1851 | char __user *buf; | 1850 | char __user *buf; |
1852 | 1851 | ||
1853 | pagevec_init(&lru_pvec, 0); | 1852 | pagevec_init(&lru_pvec, 0); |
@@ -1858,31 +1857,33 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, | |||
1858 | if (likely(nr_segs == 1)) | 1857 | if (likely(nr_segs == 1)) |
1859 | buf = iov->iov_base + written; | 1858 | buf = iov->iov_base + written; |
1860 | else { | 1859 | else { |
1861 | filemap_set_next_iovec(&cur_iov, &iov_base, written); | 1860 | filemap_set_next_iovec(&cur_iov, &iov_offset, written); |
1862 | buf = cur_iov->iov_base + iov_base; | 1861 | buf = cur_iov->iov_base + iov_offset; |
1863 | } | 1862 | } |
1864 | 1863 | ||
1865 | do { | 1864 | do { |
1866 | unsigned long index; | 1865 | pgoff_t index; /* Pagecache index for current page */ |
1867 | unsigned long offset; | 1866 | unsigned long offset; /* Offset into pagecache page */ |
1868 | unsigned long maxlen; | 1867 | unsigned long maxlen; /* Bytes remaining in current iovec */ |
1869 | size_t copied; | 1868 | size_t bytes; /* Bytes to write to page */ |
1869 | size_t copied; /* Bytes copied from user */ | ||
1870 | 1870 | ||
1871 | offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ | 1871 | offset = (pos & (PAGE_CACHE_SIZE - 1)); |
1872 | index = pos >> PAGE_CACHE_SHIFT; | 1872 | index = pos >> PAGE_CACHE_SHIFT; |
1873 | bytes = PAGE_CACHE_SIZE - offset; | 1873 | bytes = PAGE_CACHE_SIZE - offset; |
1874 | if (bytes > count) | 1874 | if (bytes > count) |
1875 | bytes = count; | 1875 | bytes = count; |
1876 | 1876 | ||
1877 | maxlen = cur_iov->iov_len - iov_offset; | ||
1878 | if (maxlen > bytes) | ||
1879 | maxlen = bytes; | ||
1880 | |||
1877 | /* | 1881 | /* |
1878 | * Bring in the user page that we will copy from _first_. | 1882 | * Bring in the user page that we will copy from _first_. |
1879 | * Otherwise there's a nasty deadlock on copying from the | 1883 | * Otherwise there's a nasty deadlock on copying from the |
1880 | * same page as we're writing to, without it being marked | 1884 | * same page as we're writing to, without it being marked |
1881 | * up-to-date. | 1885 | * up-to-date. |
1882 | */ | 1886 | */ |
1883 | maxlen = cur_iov->iov_len - iov_base; | ||
1884 | if (maxlen > bytes) | ||
1885 | maxlen = bytes; | ||
1886 | fault_in_pages_readable(buf, maxlen); | 1887 | fault_in_pages_readable(buf, maxlen); |
1887 | 1888 | ||
1888 | page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec); | 1889 | page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec); |
@@ -1913,7 +1914,7 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, | |||
1913 | buf, bytes); | 1914 | buf, bytes); |
1914 | else | 1915 | else |
1915 | copied = filemap_copy_from_user_iovec(page, offset, | 1916 | copied = filemap_copy_from_user_iovec(page, offset, |
1916 | cur_iov, iov_base, bytes); | 1917 | cur_iov, iov_offset, bytes); |
1917 | flush_dcache_page(page); | 1918 | flush_dcache_page(page); |
1918 | status = a_ops->commit_write(file, page, offset, offset+bytes); | 1919 | status = a_ops->commit_write(file, page, offset, offset+bytes); |
1919 | if (status == AOP_TRUNCATED_PAGE) { | 1920 | if (status == AOP_TRUNCATED_PAGE) { |
@@ -1931,12 +1932,12 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, | |||
1931 | buf += status; | 1932 | buf += status; |
1932 | if (unlikely(nr_segs > 1)) { | 1933 | if (unlikely(nr_segs > 1)) { |
1933 | filemap_set_next_iovec(&cur_iov, | 1934 | filemap_set_next_iovec(&cur_iov, |
1934 | &iov_base, status); | 1935 | &iov_offset, status); |
1935 | if (count) | 1936 | if (count) |
1936 | buf = cur_iov->iov_base + | 1937 | buf = cur_iov->iov_base + |
1937 | iov_base; | 1938 | iov_offset; |
1938 | } else { | 1939 | } else { |
1939 | iov_base += status; | 1940 | iov_offset += status; |
1940 | } | 1941 | } |
1941 | } | 1942 | } |
1942 | } | 1943 | } |