diff options
author | Pavel Shilovsky <pshilovsky@samba.org> | 2014-06-22 03:03:22 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2014-08-02 02:23:02 -0400 |
commit | 7f6c50086a6f5bc0fee46548afc836070a439313 (patch) | |
tree | be639b03971a6477c269a2c44860bbb0d3754400 /fs/cifs/cifssmb.c | |
parent | 66231a47965c551d3056d5104f8b06688065748c (diff) |
CIFS: Fix cifs_writev_requeue when wsize changes
If wsize changes on reconnect we need to use new writedata structure
that for retrying.
Reviewed-by: Shirish Pargaonkar <spargaonkar@suse.com>
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 84 |
1 files changed, 68 insertions, 16 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b7e5b6508caa..52cfd8cf0db0 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -1896,28 +1896,80 @@ cifs_writedata_release(struct kref *refcount) | |||
1896 | static void | 1896 | static void |
1897 | cifs_writev_requeue(struct cifs_writedata *wdata) | 1897 | cifs_writev_requeue(struct cifs_writedata *wdata) |
1898 | { | 1898 | { |
1899 | int i, rc; | 1899 | int i, rc = 0; |
1900 | struct inode *inode = wdata->cfile->dentry->d_inode; | 1900 | struct inode *inode = wdata->cfile->dentry->d_inode; |
1901 | struct TCP_Server_Info *server; | 1901 | struct TCP_Server_Info *server; |
1902 | unsigned int rest_len; | ||
1902 | 1903 | ||
1903 | for (i = 0; i < wdata->nr_pages; i++) { | 1904 | server = tlink_tcon(wdata->cfile->tlink)->ses->server; |
1904 | lock_page(wdata->pages[i]); | 1905 | i = 0; |
1905 | clear_page_dirty_for_io(wdata->pages[i]); | 1906 | rest_len = wdata->bytes; |
1906 | } | ||
1907 | |||
1908 | do { | 1907 | do { |
1909 | server = tlink_tcon(wdata->cfile->tlink)->ses->server; | 1908 | struct cifs_writedata *wdata2; |
1910 | rc = server->ops->async_writev(wdata, cifs_writedata_release); | 1909 | unsigned int j, nr_pages, wsize, tailsz, cur_len; |
1911 | } while (rc == -EAGAIN); | 1910 | |
1911 | wsize = server->ops->wp_retry_size(inode); | ||
1912 | if (wsize < rest_len) { | ||
1913 | nr_pages = wsize / PAGE_CACHE_SIZE; | ||
1914 | if (!nr_pages) { | ||
1915 | rc = -ENOTSUPP; | ||
1916 | break; | ||
1917 | } | ||
1918 | cur_len = nr_pages * PAGE_CACHE_SIZE; | ||
1919 | tailsz = PAGE_CACHE_SIZE; | ||
1920 | } else { | ||
1921 | nr_pages = DIV_ROUND_UP(rest_len, PAGE_CACHE_SIZE); | ||
1922 | cur_len = rest_len; | ||
1923 | tailsz = rest_len - (nr_pages - 1) * PAGE_CACHE_SIZE; | ||
1924 | } | ||
1912 | 1925 | ||
1913 | for (i = 0; i < wdata->nr_pages; i++) { | 1926 | wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete); |
1914 | unlock_page(wdata->pages[i]); | 1927 | if (!wdata2) { |
1915 | if (rc != 0) { | 1928 | rc = -ENOMEM; |
1916 | SetPageError(wdata->pages[i]); | 1929 | break; |
1917 | end_page_writeback(wdata->pages[i]); | ||
1918 | page_cache_release(wdata->pages[i]); | ||
1919 | } | 1930 | } |
1920 | } | 1931 | |
1932 | for (j = 0; j < nr_pages; j++) { | ||
1933 | wdata2->pages[j] = wdata->pages[i + j]; | ||
1934 | lock_page(wdata2->pages[j]); | ||
1935 | clear_page_dirty_for_io(wdata2->pages[j]); | ||
1936 | } | ||
1937 | |||
1938 | wdata2->sync_mode = wdata->sync_mode; | ||
1939 | wdata2->nr_pages = nr_pages; | ||
1940 | wdata2->offset = page_offset(wdata2->pages[0]); | ||
1941 | wdata2->pagesz = PAGE_CACHE_SIZE; | ||
1942 | wdata2->tailsz = tailsz; | ||
1943 | wdata2->bytes = cur_len; | ||
1944 | |||
1945 | wdata2->cfile = find_writable_file(CIFS_I(inode), false); | ||
1946 | if (!wdata2->cfile) { | ||
1947 | cifs_dbg(VFS, "No writable handles for inode\n"); | ||
1948 | rc = -EBADF; | ||
1949 | break; | ||
1950 | } | ||
1951 | wdata2->pid = wdata2->cfile->pid; | ||
1952 | rc = server->ops->async_writev(wdata2, cifs_writedata_release); | ||
1953 | |||
1954 | for (j = 0; j < nr_pages; j++) { | ||
1955 | unlock_page(wdata2->pages[j]); | ||
1956 | if (rc != 0 && rc != -EAGAIN) { | ||
1957 | SetPageError(wdata2->pages[j]); | ||
1958 | end_page_writeback(wdata2->pages[j]); | ||
1959 | page_cache_release(wdata2->pages[j]); | ||
1960 | } | ||
1961 | } | ||
1962 | |||
1963 | if (rc) { | ||
1964 | kref_put(&wdata2->refcount, cifs_writedata_release); | ||
1965 | if (rc == -EAGAIN) | ||
1966 | continue; | ||
1967 | break; | ||
1968 | } | ||
1969 | |||
1970 | rest_len -= cur_len; | ||
1971 | i += nr_pages; | ||
1972 | } while (i < wdata->nr_pages); | ||
1921 | 1973 | ||
1922 | mapping_set_error(inode->i_mapping, rc); | 1974 | mapping_set_error(inode->i_mapping, rc); |
1923 | kref_put(&wdata->refcount, cifs_writedata_release); | 1975 | kref_put(&wdata->refcount, cifs_writedata_release); |