aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2005-10-05 17:50:29 -0400
committerSteve French <sfrench@us.ibm.com>2005-10-05 17:50:29 -0400
commit37c0eb4677f733a773df6287b0f73f00274402e3 (patch)
tree29d6da2f609bdc22316b24aca866ad2ee2093959 /fs/cifs
parent6148a742b2bd76abfe0c1fc50dd747cb9f28cd6b (diff)
CIFS: implement cifs_writepages to perform multi-page I/O
Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/file.c191
-rw-r--r--fs/cifs/transport.c10
2 files changed, 190 insertions, 11 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 94875455d7fa..0473b221f643 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -21,11 +21,14 @@
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */ 22 */
23#include <linux/fs.h> 23#include <linux/fs.h>
24#include <linux/backing-dev.h>
24#include <linux/stat.h> 25#include <linux/stat.h>
25#include <linux/fcntl.h> 26#include <linux/fcntl.h>
27#include <linux/mpage.h>
26#include <linux/pagemap.h> 28#include <linux/pagemap.h>
27#include <linux/pagevec.h> 29#include <linux/pagevec.h>
28#include <linux/smp_lock.h> 30#include <linux/smp_lock.h>
31#include <linux/writeback.h>
29#include <asm/div64.h> 32#include <asm/div64.h>
30#include "cifsfs.h" 33#include "cifsfs.h"
31#include "cifspdu.h" 34#include "cifspdu.h"
@@ -916,6 +919,16 @@ static struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
916 ((open_file->pfile->f_flags & O_RDWR) || 919 ((open_file->pfile->f_flags & O_RDWR) ||
917 (open_file->pfile->f_flags & O_WRONLY))) { 920 (open_file->pfile->f_flags & O_WRONLY))) {
918 read_unlock(&GlobalSMBSeslock); 921 read_unlock(&GlobalSMBSeslock);
922 if(open_file->invalidHandle) {
923 rc = cifs_reopen_file(cifs_inode->vfs_inode,
924 open_file->pfile, FALSE);
925 /* if it fails, try another handle - might be */
926 /* dangerous to hold up writepages with retry */
927 if(rc) {
928 read_lock(&GlobalSMBSeslock);
929 continue;
930 }
931 }
919 return open_file; 932 return open_file;
920 } 933 }
921 } 934 }
@@ -982,20 +995,181 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
982 return rc; 995 return rc;
983} 996}
984 997
985#if 0 998#ifdef CONFIG_CIFS_EXPERIMENTAL
986static int cifs_writepages(struct address_space *mapping, 999static int cifs_writepages(struct address_space *mapping,
987 struct writeback_control *wbc) 1000 struct writeback_control *wbc)
988{ 1001{
989 int rc = -EFAULT; 1002 struct backing_dev_info *bdi = mapping->backing_dev_info;
1003 unsigned int bytes_to_write;
1004 unsigned int bytes_written;
1005 struct cifs_sb_info *cifs_sb;
1006 int done = 0;
1007 pgoff_t end = -1;
1008 pgoff_t index;
1009 int is_range = 0;
1010 struct kvec iov[32];
1011 int n_iov = 0;
1012 pgoff_t next;
1013 int nr_pages;
1014 __u64 offset = 0;
1015 struct cifsFileInfo *open_file = NULL;
1016 struct page *page;
1017 struct pagevec pvec;
1018 int rc = 0;
1019 int scanned = 0;
990 int xid; 1020 int xid;
991 1021
1022 cifs_sb = CIFS_SB(mapping->host->i_sb);
1023
1024 /*
1025 * If wsize is smaller that the page cache size, default to writing
1026 * one page at a time via cifs_writepage
1027 */
1028 if (cifs_sb->wsize < PAGE_CACHE_SIZE)
1029 return generic_writepages(mapping, wbc);
1030
1031 /*
1032 * BB: Is this meaningful for a non-block-device file system?
1033 * If it is, we should test it again after we do I/O
1034 */
1035 if (wbc->nonblocking && bdi_write_congested(bdi)) {
1036 wbc->encountered_congestion = 1;
1037 return 0;
1038 }
1039
992 xid = GetXid(); 1040 xid = GetXid();
993 1041
994 /* Find contiguous pages then iterate through repeating 1042 pagevec_init(&pvec, 0);
995 call 16K write then Setpageuptodate or if LARGE_WRITE_X 1043 if (wbc->sync_mode == WB_SYNC_NONE)
996 support then send larger writes via kevec so as to eliminate 1044 index = mapping->writeback_index; /* Start from prev offset */
997 a memcpy */ 1045 else {
1046 index = 0;
1047 scanned = 1;
1048 }
1049 if (wbc->start || wbc->end) {
1050 index = wbc->start >> PAGE_CACHE_SHIFT;
1051 end = wbc->end >> PAGE_CACHE_SHIFT;
1052 is_range = 1;
1053 scanned = 1;
1054 }
1055retry:
1056 while (!done && (index <= end) &&
1057 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
1058 PAGECACHE_TAG_DIRTY,
1059 min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
1060 int first;
1061 unsigned int i;
1062
1063 if (!open_file) {
1064 open_file = find_writable_file(CIFS_I(mapping->host));
1065 if (!open_file) {
1066 pagevec_release(&pvec);
1067 cERROR(1, ("No writable handles for inode"));
1068 return -EIO;
1069 }
1070 }
1071
1072 first = -1;
1073 next = 0;
1074 n_iov = 0;
1075 bytes_to_write = 0;
1076
1077 for (i = 0; i < nr_pages; i++) {
1078 page = pvec.pages[i];
1079 /*
1080 * At this point we hold neither mapping->tree_lock nor
1081 * lock on the page itself: the page may be truncated or
1082 * invalidated (changing page->mapping to NULL), or even
1083 * swizzled back from swapper_space to tmpfs file
1084 * mapping
1085 */
1086
1087 if (first < 0)
1088 lock_page(page);
1089 else if (TestSetPageLocked(page))
1090 break;
1091
1092 if (unlikely(page->mapping != mapping)) {
1093 unlock_page(page);
1094 break;
1095 }
1096
1097 if (unlikely(is_range) && (page->index > end)) {
1098 done = 1;
1099 unlock_page(page);
1100 break;
1101 }
1102
1103 if (next && (page->index != next)) {
1104 /* Not next consecutive page */
1105 unlock_page(page);
1106 break;
1107 }
1108
1109 if (wbc->sync_mode != WB_SYNC_NONE)
1110 wait_on_page_writeback(page);
1111
1112 if (PageWriteback(page) ||
1113 !test_clear_page_dirty(page)) {
1114 unlock_page(page);
1115 break;
1116 }
1117 /*
1118 * BB can we get rid of this? pages are held by pvec
1119 */
1120 page_cache_get(page);
1121
1122 /* reserve iov[0] for the smb header */
1123 n_iov++;
1124 iov[n_iov].iov_base = kmap(page);
1125 iov[n_iov].iov_len = PAGE_CACHE_SIZE;
1126 bytes_to_write += PAGE_CACHE_SIZE;
1127
1128 if (first < 0) {
1129 first = i;
1130 offset = page_offset(page);
1131 }
1132 next = page->index + 1;
1133 if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
1134 break;
1135 }
1136 if (n_iov) {
1137 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1138 open_file->netfid, bytes_to_write,
1139 offset, &bytes_written, iov, n_iov,
1140 1);
1141 if (rc || bytes_written < bytes_to_write) {
1142 cERROR(1,("CIFSSMBWrite2 returned %d, written = %x",
1143 rc, bytes_written));
1144 set_bit(AS_EIO, &mapping->flags);
1145 SetPageError(page);
1146 }
1147 for (i = 0; i < n_iov; i++) {
1148 page = pvec.pages[first + i];
1149 kunmap(page);
1150 unlock_page(page);
1151 page_cache_release(page);
1152 }
1153 if ((wbc->nr_to_write -= n_iov) <= 0)
1154 done = 1;
1155 index = next;
1156 }
1157 pagevec_release(&pvec);
1158 }
1159 if (!scanned && !done) {
1160 /*
1161 * We hit the last page and there is more work to be done: wrap
1162 * back to the start of the file
1163 */
1164 scanned = 1;
1165 index = 0;
1166 goto retry;
1167 }
1168 if (!is_range)
1169 mapping->writeback_index = index;
1170
998 FreeXid(xid); 1171 FreeXid(xid);
1172
999 return rc; 1173 return rc;
1000} 1174}
1001#endif 1175#endif
@@ -1635,6 +1809,9 @@ struct address_space_operations cifs_addr_ops = {
1635 .readpage = cifs_readpage, 1809 .readpage = cifs_readpage,
1636 .readpages = cifs_readpages, 1810 .readpages = cifs_readpages,
1637 .writepage = cifs_writepage, 1811 .writepage = cifs_writepage,
1812#ifdef CONFIG_CIFS_EXPERIMENTAL
1813 .writepages = cifs_writepages,
1814#endif
1638 .prepare_write = cifs_prepare_write, 1815 .prepare_write = cifs_prepare_write,
1639 .commit_write = cifs_commit_write, 1816 .commit_write = cifs_commit_write,
1640 .set_page_dirty = __set_page_dirty_nobuffers, 1817 .set_page_dirty = __set_page_dirty_nobuffers,
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 64c712629f27..e104c1ad2da3 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -395,7 +395,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
395 if (long_op == -1) 395 if (long_op == -1)
396 goto cifs_no_response_exit2; 396 goto cifs_no_response_exit2;
397 else if (long_op == 2) /* writes past end of file can take loong time */ 397 else if (long_op == 2) /* writes past end of file can take loong time */
398 timeout = 300 * HZ; 398 timeout = 180 * HZ;
399 else if (long_op == 1) 399 else if (long_op == 1)
400 timeout = 45 * HZ; /* should be greater than 400 timeout = 45 * HZ; /* should be greater than
401 servers oplock break timeout (about 43 seconds) */ 401 servers oplock break timeout (about 43 seconds) */
@@ -431,7 +431,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
431 spin_unlock(&GlobalMid_Lock); 431 spin_unlock(&GlobalMid_Lock);
432 receive_len = midQ->resp_buf->smb_buf_length; 432 receive_len = midQ->resp_buf->smb_buf_length;
433 } else { 433 } else {
434 cERROR(1,("No response buffer")); 434 cERROR(1,("No response to cmd %d mid %d",
435 midQ->command, midQ->mid));
435 if(midQ->midState == MID_REQUEST_SUBMITTED) { 436 if(midQ->midState == MID_REQUEST_SUBMITTED) {
436 if(ses->server->tcpStatus == CifsExiting) 437 if(ses->server->tcpStatus == CifsExiting)
437 rc = -EHOSTDOWN; 438 rc = -EHOSTDOWN;
@@ -646,7 +647,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
646 if (long_op == -1) 647 if (long_op == -1)
647 goto cifs_no_response_exit; 648 goto cifs_no_response_exit;
648 else if (long_op == 2) /* writes past end of file can take loong time */ 649 else if (long_op == 2) /* writes past end of file can take loong time */
649 timeout = 300 * HZ; 650 timeout = 180 * HZ;
650 else if (long_op == 1) 651 else if (long_op == 1)
651 timeout = 45 * HZ; /* should be greater than 652 timeout = 45 * HZ; /* should be greater than
652 servers oplock break timeout (about 43 seconds) */ 653 servers oplock break timeout (about 43 seconds) */
@@ -682,7 +683,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
682 spin_unlock(&GlobalMid_Lock); 683 spin_unlock(&GlobalMid_Lock);
683 receive_len = midQ->resp_buf->smb_buf_length; 684 receive_len = midQ->resp_buf->smb_buf_length;
684 } else { 685 } else {
685 cERROR(1,("No response buffer")); 686 cERROR(1,("No response for cmd %d mid %d",
687 midQ->command, midQ->mid));
686 if(midQ->midState == MID_REQUEST_SUBMITTED) { 688 if(midQ->midState == MID_REQUEST_SUBMITTED) {
687 if(ses->server->tcpStatus == CifsExiting) 689 if(ses->server->tcpStatus == CifsExiting)
688 rc = -EHOSTDOWN; 690 rc = -EHOSTDOWN;