diff options
author | Pavel Shilovsky <pshilovsky@samba.org> | 2014-06-19 07:01:03 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2014-08-02 02:23:01 -0400 |
commit | 7e48ff82026d99fe498a280faa55e5842288d72f (patch) | |
tree | 3f3e59c19eed9f19b3ce60578605477f8746866b /fs/cifs | |
parent | 038bc961c31b070269ecd07349a7ee2e839d4fec (diff) |
CIFS: Separate page processing from writepages
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org>
Reviewed-by: Jeff Layton <jlayton@samba.org>
Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/file.c | 152 |
1 files changed, 82 insertions, 70 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 6b6df30cfd89..69d176396d04 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1878,6 +1878,86 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
1878 | return rc; | 1878 | return rc; |
1879 | } | 1879 | } |
1880 | 1880 | ||
1881 | static unsigned int | ||
1882 | wdata_prepare_pages(struct cifs_writedata *wdata, unsigned int found_pages, | ||
1883 | struct address_space *mapping, | ||
1884 | struct writeback_control *wbc, | ||
1885 | pgoff_t end, pgoff_t *index, pgoff_t *next, bool *done) | ||
1886 | { | ||
1887 | unsigned int nr_pages = 0, i; | ||
1888 | struct page *page; | ||
1889 | |||
1890 | for (i = 0; i < found_pages; i++) { | ||
1891 | page = wdata->pages[i]; | ||
1892 | /* | ||
1893 | * At this point we hold neither mapping->tree_lock nor | ||
1894 | * lock on the page itself: the page may be truncated or | ||
1895 | * invalidated (changing page->mapping to NULL), or even | ||
1896 | * swizzled back from swapper_space to tmpfs file | ||
1897 | * mapping | ||
1898 | */ | ||
1899 | |||
1900 | if (nr_pages == 0) | ||
1901 | lock_page(page); | ||
1902 | else if (!trylock_page(page)) | ||
1903 | break; | ||
1904 | |||
1905 | if (unlikely(page->mapping != mapping)) { | ||
1906 | unlock_page(page); | ||
1907 | break; | ||
1908 | } | ||
1909 | |||
1910 | if (!wbc->range_cyclic && page->index > end) { | ||
1911 | *done = true; | ||
1912 | unlock_page(page); | ||
1913 | break; | ||
1914 | } | ||
1915 | |||
1916 | if (*next && (page->index != *next)) { | ||
1917 | /* Not next consecutive page */ | ||
1918 | unlock_page(page); | ||
1919 | break; | ||
1920 | } | ||
1921 | |||
1922 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
1923 | wait_on_page_writeback(page); | ||
1924 | |||
1925 | if (PageWriteback(page) || | ||
1926 | !clear_page_dirty_for_io(page)) { | ||
1927 | unlock_page(page); | ||
1928 | break; | ||
1929 | } | ||
1930 | |||
1931 | /* | ||
1932 | * This actually clears the dirty bit in the radix tree. | ||
1933 | * See cifs_writepage() for more commentary. | ||
1934 | */ | ||
1935 | set_page_writeback(page); | ||
1936 | if (page_offset(page) >= i_size_read(mapping->host)) { | ||
1937 | *done = true; | ||
1938 | unlock_page(page); | ||
1939 | end_page_writeback(page); | ||
1940 | break; | ||
1941 | } | ||
1942 | |||
1943 | wdata->pages[i] = page; | ||
1944 | *next = page->index + 1; | ||
1945 | ++nr_pages; | ||
1946 | } | ||
1947 | |||
1948 | /* reset index to refind any pages skipped */ | ||
1949 | if (nr_pages == 0) | ||
1950 | *index = wdata->pages[0]->index + 1; | ||
1951 | |||
1952 | /* put any pages we aren't going to use */ | ||
1953 | for (i = nr_pages; i < found_pages; i++) { | ||
1954 | page_cache_release(wdata->pages[i]); | ||
1955 | wdata->pages[i] = NULL; | ||
1956 | } | ||
1957 | |||
1958 | return nr_pages; | ||
1959 | } | ||
1960 | |||
1881 | static int cifs_writepages(struct address_space *mapping, | 1961 | static int cifs_writepages(struct address_space *mapping, |
1882 | struct writeback_control *wbc) | 1962 | struct writeback_control *wbc) |
1883 | { | 1963 | { |
@@ -1886,7 +1966,6 @@ static int cifs_writepages(struct address_space *mapping, | |||
1886 | pgoff_t end, index; | 1966 | pgoff_t end, index; |
1887 | struct cifs_writedata *wdata; | 1967 | struct cifs_writedata *wdata; |
1888 | struct TCP_Server_Info *server; | 1968 | struct TCP_Server_Info *server; |
1889 | struct page *page; | ||
1890 | int rc = 0; | 1969 | int rc = 0; |
1891 | 1970 | ||
1892 | /* | 1971 | /* |
@@ -1944,75 +2023,8 @@ retry: | |||
1944 | break; | 2023 | break; |
1945 | } | 2024 | } |
1946 | 2025 | ||
1947 | nr_pages = 0; | 2026 | nr_pages = wdata_prepare_pages(wdata, found_pages, mapping, wbc, |
1948 | for (i = 0; i < found_pages; i++) { | 2027 | end, &index, &next, &done); |
1949 | page = wdata->pages[i]; | ||
1950 | /* | ||
1951 | * At this point we hold neither mapping->tree_lock nor | ||
1952 | * lock on the page itself: the page may be truncated or | ||
1953 | * invalidated (changing page->mapping to NULL), or even | ||
1954 | * swizzled back from swapper_space to tmpfs file | ||
1955 | * mapping | ||
1956 | */ | ||
1957 | |||
1958 | if (nr_pages == 0) | ||
1959 | lock_page(page); | ||
1960 | else if (!trylock_page(page)) | ||
1961 | break; | ||
1962 | |||
1963 | if (unlikely(page->mapping != mapping)) { | ||
1964 | unlock_page(page); | ||
1965 | break; | ||
1966 | } | ||
1967 | |||
1968 | if (!wbc->range_cyclic && page->index > end) { | ||
1969 | done = true; | ||
1970 | unlock_page(page); | ||
1971 | break; | ||
1972 | } | ||
1973 | |||
1974 | if (next && (page->index != next)) { | ||
1975 | /* Not next consecutive page */ | ||
1976 | unlock_page(page); | ||
1977 | break; | ||
1978 | } | ||
1979 | |||
1980 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
1981 | wait_on_page_writeback(page); | ||
1982 | |||
1983 | if (PageWriteback(page) || | ||
1984 | !clear_page_dirty_for_io(page)) { | ||
1985 | unlock_page(page); | ||
1986 | break; | ||
1987 | } | ||
1988 | |||
1989 | /* | ||
1990 | * This actually clears the dirty bit in the radix tree. | ||
1991 | * See cifs_writepage() for more commentary. | ||
1992 | */ | ||
1993 | set_page_writeback(page); | ||
1994 | |||
1995 | if (page_offset(page) >= i_size_read(mapping->host)) { | ||
1996 | done = true; | ||
1997 | unlock_page(page); | ||
1998 | end_page_writeback(page); | ||
1999 | break; | ||
2000 | } | ||
2001 | |||
2002 | wdata->pages[i] = page; | ||
2003 | next = page->index + 1; | ||
2004 | ++nr_pages; | ||
2005 | } | ||
2006 | |||
2007 | /* reset index to refind any pages skipped */ | ||
2008 | if (nr_pages == 0) | ||
2009 | index = wdata->pages[0]->index + 1; | ||
2010 | |||
2011 | /* put any pages we aren't going to use */ | ||
2012 | for (i = nr_pages; i < found_pages; i++) { | ||
2013 | page_cache_release(wdata->pages[i]); | ||
2014 | wdata->pages[i] = NULL; | ||
2015 | } | ||
2016 | 2028 | ||
2017 | /* nothing to write? */ | 2029 | /* nothing to write? */ |
2018 | if (nr_pages == 0) { | 2030 | if (nr_pages == 0) { |