Commit 7f6c50086a6f5bc0fee46548afc836070a439313

Authored by Pavel Shilovsky
Committed by Steve French
1 parent 66231a4796

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

... ... @@ -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 {
... ... @@ -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);
... ... @@ -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,
... ... @@ -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 = {