diff options
| -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 | } |
