Commit 7f6c50086a6f5bc0fee46548afc836070a439313
Committed by
Steve French
1 parent
66231a4796
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
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>
Showing 4 changed files with 87 additions and 16 deletions Side-by-side Diff
fs/cifs/cifsglob.h
... | ... | @@ -404,6 +404,8 @@ |
404 | 404 | const struct cifs_fid *, u32 *); |
405 | 405 | int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *, |
406 | 406 | int); |
407 | + /* writepages retry size */ | |
408 | + unsigned int (*wp_retry_size)(struct inode *); | |
407 | 409 | }; |
408 | 410 | |
409 | 411 | struct smb_version_values { |
fs/cifs/cifssmb.c
... | ... | @@ -1896,28 +1896,80 @@ |
1896 | 1896 | static void |
1897 | 1897 | cifs_writev_requeue(struct cifs_writedata *wdata) |
1898 | 1898 | { |
1899 | - int i, rc; | |
1899 | + int i, rc = 0; | |
1900 | 1900 | struct inode *inode = wdata->cfile->dentry->d_inode; |
1901 | 1901 | struct TCP_Server_Info *server; |
1902 | + unsigned int rest_len; | |
1902 | 1903 | |
1903 | - for (i = 0; i < wdata->nr_pages; i++) { | |
1904 | - lock_page(wdata->pages[i]); | |
1905 | - clear_page_dirty_for_io(wdata->pages[i]); | |
1906 | - } | |
1907 | - | |
1904 | + server = tlink_tcon(wdata->cfile->tlink)->ses->server; | |
1905 | + i = 0; | |
1906 | + rest_len = wdata->bytes; | |
1908 | 1907 | do { |
1909 | - server = tlink_tcon(wdata->cfile->tlink)->ses->server; | |
1910 | - rc = server->ops->async_writev(wdata, cifs_writedata_release); | |
1911 | - } while (rc == -EAGAIN); | |
1908 | + struct cifs_writedata *wdata2; | |
1909 | + unsigned int j, nr_pages, wsize, tailsz, cur_len; | |
1912 | 1910 | |
1913 | - for (i = 0; i < wdata->nr_pages; i++) { | |
1914 | - unlock_page(wdata->pages[i]); | |
1915 | - if (rc != 0) { | |
1916 | - SetPageError(wdata->pages[i]); | |
1917 | - end_page_writeback(wdata->pages[i]); | |
1918 | - page_cache_release(wdata->pages[i]); | |
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; | |
1919 | 1924 | } |
1920 | - } | |
1925 | + | |
1926 | + wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete); | |
1927 | + if (!wdata2) { | |
1928 | + rc = -ENOMEM; | |
1929 | + break; | |
1930 | + } | |
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 | 1974 | mapping_set_error(inode->i_mapping, rc); |
1923 | 1975 | kref_put(&wdata->refcount, cifs_writedata_release); |
fs/cifs/smb1ops.c
... | ... | @@ -1009,6 +1009,12 @@ |
1009 | 1009 | return oplock == OPLOCK_READ; |
1010 | 1010 | } |
1011 | 1011 | |
1012 | +static unsigned int | |
1013 | +cifs_wp_retry_size(struct inode *inode) | |
1014 | +{ | |
1015 | + return CIFS_SB(inode->i_sb)->wsize; | |
1016 | +} | |
1017 | + | |
1012 | 1018 | struct smb_version_operations smb1_operations = { |
1013 | 1019 | .send_cancel = send_nt_cancel, |
1014 | 1020 | .compare_fids = cifs_compare_fids, |
... | ... | @@ -1078,6 +1084,7 @@ |
1078 | 1084 | .query_mf_symlink = cifs_query_mf_symlink, |
1079 | 1085 | .create_mf_symlink = cifs_create_mf_symlink, |
1080 | 1086 | .is_read_op = cifs_is_read_op, |
1087 | + .wp_retry_size = cifs_wp_retry_size, | |
1081 | 1088 | #ifdef CONFIG_CIFS_XATTR |
1082 | 1089 | .query_all_EAs = CIFSSMBQAllEAs, |
1083 | 1090 | .set_EA = CIFSSMBSetEA, |
fs/cifs/smb2ops.c
... | ... | @@ -1104,6 +1104,13 @@ |
1104 | 1104 | return le32_to_cpu(lc->lcontext.LeaseState); |
1105 | 1105 | } |
1106 | 1106 | |
1107 | +static unsigned int | |
1108 | +smb2_wp_retry_size(struct inode *inode) | |
1109 | +{ | |
1110 | + return min_t(unsigned int, CIFS_SB(inode->i_sb)->wsize, | |
1111 | + SMB2_MAX_BUFFER_SIZE); | |
1112 | +} | |
1113 | + | |
1107 | 1114 | struct smb_version_operations smb20_operations = { |
1108 | 1115 | .compare_fids = smb2_compare_fids, |
1109 | 1116 | .setup_request = smb2_setup_request, |
... | ... | @@ -1177,6 +1184,7 @@ |
1177 | 1184 | .create_lease_buf = smb2_create_lease_buf, |
1178 | 1185 | .parse_lease_buf = smb2_parse_lease_buf, |
1179 | 1186 | .clone_range = smb2_clone_range, |
1187 | + .wp_retry_size = smb2_wp_retry_size, | |
1180 | 1188 | }; |
1181 | 1189 | |
1182 | 1190 | struct smb_version_operations smb21_operations = { |
... | ... | @@ -1252,6 +1260,7 @@ |
1252 | 1260 | .create_lease_buf = smb2_create_lease_buf, |
1253 | 1261 | .parse_lease_buf = smb2_parse_lease_buf, |
1254 | 1262 | .clone_range = smb2_clone_range, |
1263 | + .wp_retry_size = smb2_wp_retry_size, | |
1255 | 1264 | }; |
1256 | 1265 | |
1257 | 1266 | struct smb_version_operations smb30_operations = { |
... | ... | @@ -1330,6 +1339,7 @@ |
1330 | 1339 | .parse_lease_buf = smb3_parse_lease_buf, |
1331 | 1340 | .clone_range = smb2_clone_range, |
1332 | 1341 | .validate_negotiate = smb3_validate_negotiate, |
1342 | + .wp_retry_size = smb2_wp_retry_size, | |
1333 | 1343 | }; |
1334 | 1344 | |
1335 | 1345 | struct smb_version_values smb20_values = { |