diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 64 |
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 | */ | ||
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 | ssize_t cifs_user_write(struct file *file, const char __user *write_data, | 1008 | ssize_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)); |