aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifssmb.c
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2014-06-22 03:03:22 -0400
committerSteve French <smfrench@gmail.com>2014-08-02 02:23:02 -0400
commit7f6c50086a6f5bc0fee46548afc836070a439313 (patch)
treebe639b03971a6477c269a2c44860bbb0d3754400 /fs/cifs/cifssmb.c
parent66231a47965c551d3056d5104f8b06688065748c (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.c84
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)
1896static void 1896static void
1897cifs_writev_requeue(struct cifs_writedata *wdata) 1897cifs_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);