aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/file.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2009-04-03 13:44:00 -0400
committerSteve French <sfrench@us.ibm.com>2009-04-16 21:26:49 -0400
commitfbec9ab952d4810960e620035c8e95f0fbbae4be (patch)
treee4d8ef8e0fbe2703d98390d96151cbf40d32f434 /fs/cifs/file.c
parentd036f50fc202e1a851a25dc5edc215ebd0086201 (diff)
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>
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r--fs/cifs/file.c64
1 files changed, 50 insertions, 14 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 81747acca4c4..dfd3e6c52a1e 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -971,6 +971,40 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
971 return rc; 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 */
986static int
987cifs_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 */
998static void
999cifs_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
974ssize_t cifs_user_write(struct file *file, const char __user *write_data, 1008ssize_t cifs_user_write(struct file *file, const char __user *write_data,
975 size_t write_size, loff_t *poffset) 1009 size_t write_size, loff_t *poffset)
976{ 1010{
@@ -981,6 +1015,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
981 struct cifsTconInfo *pTcon; 1015 struct cifsTconInfo *pTcon;
982 int xid, long_op; 1016 int xid, long_op;
983 struct cifsFileInfo *open_file; 1017 struct cifsFileInfo *open_file;
1018 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
984 1019
985 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 1020 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
986 1021
@@ -1000,11 +1035,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
1000 1035
1001 xid = GetXid(); 1036 xid = GetXid();
1002 1037
1003 if (*poffset > file->f_path.dentry->d_inode->i_size) 1038 long_op = cifs_write_timeout(cifsi, *poffset);
1004 long_op = CIFS_VLONG_OP; /* writes past EOF take long time */
1005 else
1006 long_op = CIFS_LONG_OP;
1007
1008 for (total_written = 0; write_size > total_written; 1039 for (total_written = 0; write_size > total_written;
1009 total_written += bytes_written) { 1040 total_written += bytes_written) {
1010 rc = -EAGAIN; 1041 rc = -EAGAIN;
@@ -1048,8 +1079,10 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
1048 FreeXid(xid); 1079 FreeXid(xid);
1049 return rc; 1080 return rc;
1050 } 1081 }
1051 } else 1082 } else {
1083 cifs_update_eof(cifsi, *poffset, bytes_written);
1052 *poffset += bytes_written; 1084 *poffset += bytes_written;
1085 }
1053 long_op = CIFS_STD_OP; /* subsequent writes fast - 1086 long_op = CIFS_STD_OP; /* subsequent writes fast -
1054 15 seconds is plenty */ 1087 15 seconds is plenty */
1055 } 1088 }
@@ -1085,6 +1118,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
1085 struct cifsTconInfo *pTcon; 1118 struct cifsTconInfo *pTcon;
1086 int xid, long_op; 1119 int xid, long_op;
1087 struct cifsFileInfo *open_file; 1120 struct cifsFileInfo *open_file;
1121 struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
1088 1122
1089 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 1123 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
1090 1124
@@ -1099,11 +1133,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
1099 1133
1100 xid = GetXid(); 1134 xid = GetXid();
1101 1135
1102 if (*poffset > file->f_path.dentry->d_inode->i_size) 1136 long_op = cifs_write_timeout(cifsi, *poffset);
1103 long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */
1104 else
1105 long_op = CIFS_LONG_OP;
1106
1107 for (total_written = 0; write_size > total_written; 1137 for (total_written = 0; write_size > total_written;
1108 total_written += bytes_written) { 1138 total_written += bytes_written) {
1109 rc = -EAGAIN; 1139 rc = -EAGAIN;
@@ -1166,8 +1196,10 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
1166 FreeXid(xid); 1196 FreeXid(xid);
1167 return rc; 1197 return rc;
1168 } 1198 }
1169 } else 1199 } else {
1200 cifs_update_eof(cifsi, *poffset, bytes_written);
1170 *poffset += bytes_written; 1201 *poffset += bytes_written;
1202 }
1171 long_op = CIFS_STD_OP; /* subsequent writes fast - 1203 long_op = CIFS_STD_OP; /* subsequent writes fast -
1172 15 seconds is plenty */ 1204 15 seconds is plenty */
1173 } 1205 }
@@ -1380,11 +1412,12 @@ static int cifs_writepages(struct address_space *mapping,
1380 int nr_pages; 1412 int nr_pages;
1381 __u64 offset = 0; 1413 __u64 offset = 0;
1382 struct cifsFileInfo *open_file; 1414 struct cifsFileInfo *open_file;
1415 struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
1383 struct page *page; 1416 struct page *page;
1384 struct pagevec pvec; 1417 struct pagevec pvec;
1385 int rc = 0; 1418 int rc = 0;
1386 int scanned = 0; 1419 int scanned = 0;
1387 int xid; 1420 int xid, long_op;
1388 1421
1389 cifs_sb = CIFS_SB(mapping->host->i_sb); 1422 cifs_sb = CIFS_SB(mapping->host->i_sb);
1390 1423
@@ -1528,12 +1561,15 @@ retry:
1528 cERROR(1, ("No writable handles for inode")); 1561 cERROR(1, ("No writable handles for inode"));
1529 rc = -EBADF; 1562 rc = -EBADF;
1530 } else { 1563 } else {
1564 long_op = cifs_write_timeout(cifsi, offset);
1531 rc = CIFSSMBWrite2(xid, cifs_sb->tcon, 1565 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1532 open_file->netfid, 1566 open_file->netfid,
1533 bytes_to_write, offset, 1567 bytes_to_write, offset,
1534 &bytes_written, iov, n_iov, 1568 &bytes_written, iov, n_iov,
1535 CIFS_LONG_OP); 1569 long_op);
1536 atomic_dec(&open_file->wrtPending); 1570 atomic_dec(&open_file->wrtPending);
1571 cifs_update_eof(cifsi, offset, bytes_written);
1572
1537 if (rc || bytes_written < bytes_to_write) { 1573 if (rc || bytes_written < bytes_to_write) {
1538 cERROR(1, ("Write2 ret %d, wrote %d", 1574 cERROR(1, ("Write2 ret %d, wrote %d",
1539 rc, bytes_written)); 1575 rc, bytes_written));