aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/cifs/cifsfs.c1
-rw-r--r--fs/cifs/cifsglob.h1
-rw-r--r--fs/cifs/cifssmb.c4
-rw-r--r--fs/cifs/file.c64
-rw-r--r--fs/cifs/inode.c8
-rw-r--r--fs/cifs/readdir.c2
6 files changed, 61 insertions, 19 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 38491fd3871d..34f5701d9555 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -316,6 +316,7 @@ cifs_alloc_inode(struct super_block *sb)
316 cifs_inode->clientCanCacheAll = false; 316 cifs_inode->clientCanCacheAll = false;
317 cifs_inode->delete_pending = false; 317 cifs_inode->delete_pending = false;
318 cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ 318 cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
319 cifs_inode->server_eof = 0;
319 320
320 /* Can not set i_flags here - they get immediately overwritten 321 /* Can not set i_flags here - they get immediately overwritten
321 to zero by the VFS */ 322 to zero by the VFS */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 9fbf4dff5da6..7ae19868fdc4 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -370,6 +370,7 @@ struct cifsInodeInfo {
370 bool clientCanCacheAll:1; /* read and writebehind oplock */ 370 bool clientCanCacheAll:1; /* read and writebehind oplock */
371 bool oplockPending:1; 371 bool oplockPending:1;
372 bool delete_pending:1; /* DELETE_ON_CLOSE is set */ 372 bool delete_pending:1; /* DELETE_ON_CLOSE is set */
373 u64 server_eof; /* current file size on server */
373 struct inode vfs_inode; 374 struct inode vfs_inode;
374}; 375};
375 376
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 3f36b1ea03c9..a0845dc7b8a9 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1626,6 +1626,8 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1626 int smb_hdr_len; 1626 int smb_hdr_len;
1627 int resp_buf_type = 0; 1627 int resp_buf_type = 0;
1628 1628
1629 *nbytes = 0;
1630
1629 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count)); 1631 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1630 1632
1631 if (tcon->ses->capabilities & CAP_LARGE_FILES) { 1633 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
@@ -1682,11 +1684,9 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1682 cifs_stats_inc(&tcon->num_writes); 1684 cifs_stats_inc(&tcon->num_writes);
1683 if (rc) { 1685 if (rc) {
1684 cFYI(1, ("Send error Write2 = %d", rc)); 1686 cFYI(1, ("Send error Write2 = %d", rc));
1685 *nbytes = 0;
1686 } else if (resp_buf_type == 0) { 1687 } else if (resp_buf_type == 0) {
1687 /* presumably this can not happen, but best to be safe */ 1688 /* presumably this can not happen, but best to be safe */
1688 rc = -EIO; 1689 rc = -EIO;
1689 *nbytes = 0;
1690 } else { 1690 } else {
1691 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base; 1691 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1692 *nbytes = le16_to_cpu(pSMBr->CountHigh); 1692 *nbytes = le16_to_cpu(pSMBr->CountHigh);
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));
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index fceebee39f27..09082ac85185 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -143,6 +143,7 @@ static void cifs_unix_info_to_inode(struct inode *inode,
143 143
144 inode->i_nlink = le64_to_cpu(info->Nlinks); 144 inode->i_nlink = le64_to_cpu(info->Nlinks);
145 145
146 cifsInfo->server_eof = end_of_file;
146 spin_lock(&inode->i_lock); 147 spin_lock(&inode->i_lock);
147 if (is_size_safe_to_change(cifsInfo, end_of_file)) { 148 if (is_size_safe_to_change(cifsInfo, end_of_file)) {
148 /* 149 /*
@@ -606,12 +607,12 @@ int cifs_get_inode_info(struct inode **pinode,
606 inode->i_mode |= S_IFREG; 607 inode->i_mode |= S_IFREG;
607 } 608 }
608 609
610 cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile);
609 spin_lock(&inode->i_lock); 611 spin_lock(&inode->i_lock);
610 if (is_size_safe_to_change(cifsInfo, 612 if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) {
611 le64_to_cpu(pfindData->EndOfFile))) {
612 /* can not safely shrink the file size here if the 613 /* can not safely shrink the file size here if the
613 client is writing to it due to potential races */ 614 client is writing to it due to potential races */
614 i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); 615 i_size_write(inode, cifsInfo->server_eof);
615 616
616 /* 512 bytes (2**9) is the fake blocksize that must be 617 /* 512 bytes (2**9) is the fake blocksize that must be
617 used for this calculation */ 618 used for this calculation */
@@ -1755,6 +1756,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
1755 } 1756 }
1756 1757
1757 if (rc == 0) { 1758 if (rc == 0) {
1759 cifsInode->server_eof = attrs->ia_size;
1758 rc = cifs_vmtruncate(inode, attrs->ia_size); 1760 rc = cifs_vmtruncate(inode, attrs->ia_size);
1759 cifs_truncate_page(inode->i_mapping, inode->i_size); 1761 cifs_truncate_page(inode->i_mapping, inode->i_size);
1760 } 1762 }
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index c3c3e6286af5..1a8be6228333 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -239,6 +239,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
239 if (atomic_read(&cifsInfo->inUse) == 0) 239 if (atomic_read(&cifsInfo->inUse) == 0)
240 atomic_set(&cifsInfo->inUse, 1); 240 atomic_set(&cifsInfo->inUse, 1);
241 241
242 cifsInfo->server_eof = end_of_file;
242 spin_lock(&tmp_inode->i_lock); 243 spin_lock(&tmp_inode->i_lock);
243 if (is_size_safe_to_change(cifsInfo, end_of_file)) { 244 if (is_size_safe_to_change(cifsInfo, end_of_file)) {
244 /* can not safely change the file size here if the 245 /* can not safely change the file size here if the
@@ -375,6 +376,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
375 tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); 376 tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
376 tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); 377 tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
377 378
379 cifsInfo->server_eof = end_of_file;
378 spin_lock(&tmp_inode->i_lock); 380 spin_lock(&tmp_inode->i_lock);
379 if (is_size_safe_to_change(cifsInfo, end_of_file)) { 381 if (is_size_safe_to_change(cifsInfo, end_of_file)) {
380 /* can not safely change the file size here if the 382 /* can not safely change the file size here if the