diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifsfs.c | 1 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 4 | ||||
-rw-r--r-- | fs/cifs/file.c | 64 | ||||
-rw-r--r-- | fs/cifs/inode.c | 8 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 2 |
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 | */ | ||
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)); |
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 |