cifs: vary timeout on writes past EOF based on offset (try #5)

This is the fourth version of this patch:

The first three generated a compiler warning asking for explicit curly
braces.

The first two didn't handle update the size correctly when writes that
didn't start at the eof were done.

The first patch also didn't update the size correctly when it explicitly
set via truncate().

This patch adds code to track the client's current understanding of the
size of the file on the server separate from the i_size, and then to use
this info to semi-intelligently set the timeout for writes past the EOF.

This helps prevent timeouts when trying to write large, sparse files on
windows servers.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>

authored by Jeff Layton and committed by Steve French fbec9ab9 d036f50f

+61 -19
+1
fs/cifs/cifsfs.c
··· 316 316 cifs_inode->clientCanCacheAll = false; 317 317 cifs_inode->delete_pending = false; 318 318 cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ 319 + cifs_inode->server_eof = 0; 319 320 320 321 /* Can not set i_flags here - they get immediately overwritten 321 322 to zero by the VFS */
+1
fs/cifs/cifsglob.h
··· 370 370 bool clientCanCacheAll:1; /* read and writebehind oplock */ 371 371 bool oplockPending:1; 372 372 bool delete_pending:1; /* DELETE_ON_CLOSE is set */ 373 + u64 server_eof; /* current file size on server */ 373 374 struct inode vfs_inode; 374 375 }; 375 376
+2 -2
fs/cifs/cifssmb.c
··· 1626 1626 int smb_hdr_len; 1627 1627 int resp_buf_type = 0; 1628 1628 1629 + *nbytes = 0; 1630 + 1629 1631 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count)); 1630 1632 1631 1633 if (tcon->ses->capabilities & CAP_LARGE_FILES) { ··· 1684 1682 cifs_stats_inc(&tcon->num_writes); 1685 1683 if (rc) { 1686 1684 cFYI(1, ("Send error Write2 = %d", rc)); 1687 - *nbytes = 0; 1688 1685 } else if (resp_buf_type == 0) { 1689 1686 /* presumably this can not happen, but best to be safe */ 1690 1687 rc = -EIO; 1691 - *nbytes = 0; 1692 1688 } else { 1693 1689 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base; 1694 1690 *nbytes = le16_to_cpu(pSMBr->CountHigh);
+50 -14
fs/cifs/file.c
··· 971 971 return rc; 972 972 } 973 973 974 + /* 975 + * Set the timeout on write requests past EOF. For some servers (Windows) 976 + * these calls can be very long. 977 + * 978 + * If we're writing >10M past the EOF we give a 180s timeout. Anything less 979 + * than that gets a 45s timeout. Writes not past EOF get 15s timeouts. 980 + * The 10M cutoff is totally arbitrary. A better scheme for this would be 981 + * welcome if someone wants to suggest one. 982 + * 983 + * We may be able to do a better job with this if there were some way to 984 + * declare that a file should be sparse. 985 + */ 986 + static int 987 + cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset) 988 + { 989 + if (offset <= cifsi->server_eof) 990 + return CIFS_STD_OP; 991 + else if (offset > (cifsi->server_eof + (10 * 1024 * 1024))) 992 + return CIFS_VLONG_OP; 993 + else 994 + return CIFS_LONG_OP; 995 + } 996 + 997 + /* update the file size (if needed) after a write */ 998 + static void 999 + cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, 1000 + unsigned int bytes_written) 1001 + { 1002 + loff_t end_of_write = offset + bytes_written; 1003 + 1004 + if (end_of_write > cifsi->server_eof) 1005 + cifsi->server_eof = end_of_write; 1006 + } 1007 + 974 1008 ssize_t cifs_user_write(struct file *file, const char __user *write_data, 975 1009 size_t write_size, loff_t *poffset) 976 1010 { ··· 1015 981 struct cifsTconInfo *pTcon; 1016 982 int xid, long_op; 1017 983 struct cifsFileInfo *open_file; 984 + struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode); 1018 985 1019 986 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 1020 987 ··· 1035 1000 1036 1001 xid = GetXid(); 1037 1002 1038 - if (*poffset > file->f_path.dentry->d_inode->i_size) 1039 - long_op = CIFS_VLONG_OP; /* writes past EOF take long time */ 1040 - else 1041 - long_op = CIFS_LONG_OP; 1042 - 1003 + long_op = cifs_write_timeout(cifsi, *poffset); 1043 1004 for (total_written = 0; write_size > total_written; 1044 1005 total_written += bytes_written) { 1045 1006 rc = -EAGAIN; ··· 1079 1048 FreeXid(xid); 1080 1049 return rc; 1081 1050 } 1082 - } else 1051 + } else { 1052 + cifs_update_eof(cifsi, *poffset, bytes_written); 1083 1053 *poffset += bytes_written; 1054 + } 1084 1055 long_op = CIFS_STD_OP; /* subsequent writes fast - 1085 1056 15 seconds is plenty */ 1086 1057 } ··· 1118 1085 struct cifsTconInfo *pTcon; 1119 1086 int xid, long_op; 1120 1087 struct cifsFileInfo *open_file; 1088 + struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode); 1121 1089 1122 1090 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 1123 1091 ··· 1133 1099 1134 1100 xid = GetXid(); 1135 1101 1136 - if (*poffset > file->f_path.dentry->d_inode->i_size) 1137 - long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */ 1138 - else 1139 - long_op = CIFS_LONG_OP; 1140 - 1102 + long_op = cifs_write_timeout(cifsi, *poffset); 1141 1103 for (total_written = 0; write_size > total_written; 1142 1104 total_written += bytes_written) { 1143 1105 rc = -EAGAIN; ··· 1196 1166 FreeXid(xid); 1197 1167 return rc; 1198 1168 } 1199 - } else 1169 + } else { 1170 + cifs_update_eof(cifsi, *poffset, bytes_written); 1200 1171 *poffset += bytes_written; 1172 + } 1201 1173 long_op = CIFS_STD_OP; /* subsequent writes fast - 1202 1174 15 seconds is plenty */ 1203 1175 } ··· 1412 1380 int nr_pages; 1413 1381 __u64 offset = 0; 1414 1382 struct cifsFileInfo *open_file; 1383 + struct cifsInodeInfo *cifsi = CIFS_I(mapping->host); 1415 1384 struct page *page; 1416 1385 struct pagevec pvec; 1417 1386 int rc = 0; 1418 1387 int scanned = 0; 1419 - int xid; 1388 + int xid, long_op; 1420 1389 1421 1390 cifs_sb = CIFS_SB(mapping->host->i_sb); 1422 1391 ··· 1561 1528 cERROR(1, ("No writable handles for inode")); 1562 1529 rc = -EBADF; 1563 1530 } else { 1531 + long_op = cifs_write_timeout(cifsi, offset); 1564 1532 rc = CIFSSMBWrite2(xid, cifs_sb->tcon, 1565 1533 open_file->netfid, 1566 1534 bytes_to_write, offset, 1567 1535 &bytes_written, iov, n_iov, 1568 - CIFS_LONG_OP); 1536 + long_op); 1569 1537 atomic_dec(&open_file->wrtPending); 1538 + cifs_update_eof(cifsi, offset, bytes_written); 1539 + 1570 1540 if (rc || bytes_written < bytes_to_write) { 1571 1541 cERROR(1, ("Write2 ret %d, wrote %d", 1572 1542 rc, bytes_written));
+5 -3
fs/cifs/inode.c
··· 143 143 144 144 inode->i_nlink = le64_to_cpu(info->Nlinks); 145 145 146 + cifsInfo->server_eof = end_of_file; 146 147 spin_lock(&inode->i_lock); 147 148 if (is_size_safe_to_change(cifsInfo, end_of_file)) { 148 149 /* ··· 607 606 inode->i_mode |= S_IFREG; 608 607 } 609 608 609 + cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile); 610 610 spin_lock(&inode->i_lock); 611 - if (is_size_safe_to_change(cifsInfo, 612 - le64_to_cpu(pfindData->EndOfFile))) { 611 + if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) { 613 612 /* can not safely shrink the file size here if the 614 613 client is writing to it due to potential races */ 615 - i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); 614 + i_size_write(inode, cifsInfo->server_eof); 616 615 617 616 /* 512 bytes (2**9) is the fake blocksize that must be 618 617 used for this calculation */ ··· 1756 1755 } 1757 1756 1758 1757 if (rc == 0) { 1758 + cifsInode->server_eof = attrs->ia_size; 1759 1759 rc = cifs_vmtruncate(inode, attrs->ia_size); 1760 1760 cifs_truncate_page(inode->i_mapping, inode->i_size); 1761 1761 }
+2
fs/cifs/readdir.c
··· 239 239 if (atomic_read(&cifsInfo->inUse) == 0) 240 240 atomic_set(&cifsInfo->inUse, 1); 241 241 242 + cifsInfo->server_eof = end_of_file; 242 243 spin_lock(&tmp_inode->i_lock); 243 244 if (is_size_safe_to_change(cifsInfo, end_of_file)) { 244 245 /* can not safely change the file size here if the ··· 376 375 tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); 377 376 tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); 378 377 378 + cifsInfo->server_eof = end_of_file; 379 379 spin_lock(&tmp_inode->i_lock); 380 380 if (is_size_safe_to_change(cifsInfo, end_of_file)) { 381 381 /* can not safely change the file size here if the