aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2005-12-12 23:53:18 -0500
committerSteve French <sfrench@us.ibm.com>2005-12-12 23:53:18 -0500
commitec637e3ffb6b978143652477c7c5f96c9519b691 (patch)
tree32533b8f101e1d85b3499050eef29e78480e5cae /fs
parentc89a86bb96307019867d11874ef0b86adaa0598e (diff)
[CIFS] Avoid extra large buffer allocation (and memcpy) in cifs_readpages
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/cifs_debug.c39
-rw-r--r--fs/cifs/cifsfs.c5
-rw-r--r--fs/cifs/cifsglob.h8
-rw-r--r--fs/cifs/cifspdu.h6
-rw-r--r--fs/cifs/cifsproto.h14
-rw-r--r--fs/cifs/cifssmb.c93
-rw-r--r--fs/cifs/connect.c2
-rw-r--r--fs/cifs/file.c52
-rw-r--r--fs/cifs/inode.c5
-rw-r--r--fs/cifs/misc.c2
-rw-r--r--fs/cifs/transport.c38
11 files changed, 156 insertions, 108 deletions
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 6f5d81f5eacb..f4124a32bef8 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -401,8 +401,8 @@ static read_proc_t ntlmv2_enabled_read;
401static write_proc_t ntlmv2_enabled_write; 401static write_proc_t ntlmv2_enabled_write;
402static read_proc_t packet_signing_enabled_read; 402static read_proc_t packet_signing_enabled_read;
403static write_proc_t packet_signing_enabled_write; 403static write_proc_t packet_signing_enabled_write;
404static read_proc_t quotaEnabled_read; 404static read_proc_t experimEnabled_read;
405static write_proc_t quotaEnabled_write; 405static write_proc_t experimEnabled_write;
406static read_proc_t linuxExtensionsEnabled_read; 406static read_proc_t linuxExtensionsEnabled_read;
407static write_proc_t linuxExtensionsEnabled_write; 407static write_proc_t linuxExtensionsEnabled_write;
408 408
@@ -442,9 +442,9 @@ cifs_proc_init(void)
442 pde->write_proc = oplockEnabled_write; 442 pde->write_proc = oplockEnabled_write;
443 443
444 pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs, 444 pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs,
445 quotaEnabled_read, NULL); 445 experimEnabled_read, NULL);
446 if (pde) 446 if (pde)
447 pde->write_proc = quotaEnabled_write; 447 pde->write_proc = experimEnabled_write;
448 448
449 pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, 449 pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs,
450 linuxExtensionsEnabled_read, NULL); 450 linuxExtensionsEnabled_read, NULL);
@@ -586,14 +586,13 @@ oplockEnabled_write(struct file *file, const char __user *buffer,
586} 586}
587 587
588static int 588static int
589quotaEnabled_read(char *page, char **start, off_t off, 589experimEnabled_read(char *page, char **start, off_t off,
590 int count, int *eof, void *data) 590 int count, int *eof, void *data)
591{ 591{
592 int len; 592 int len;
593 593
594 len = sprintf(page, "%d\n", experimEnabled); 594 len = sprintf(page, "%d\n", experimEnabled);
595/* could also check if quotas are enabled in kernel 595
596 as a whole first */
597 len -= off; 596 len -= off;
598 *start = page + off; 597 *start = page + off;
599 598
@@ -608,21 +607,23 @@ quotaEnabled_read(char *page, char **start, off_t off,
608 return len; 607 return len;
609} 608}
610static int 609static int
611quotaEnabled_write(struct file *file, const char __user *buffer, 610experimEnabled_write(struct file *file, const char __user *buffer,
612 unsigned long count, void *data) 611 unsigned long count, void *data)
613{ 612{
614 char c; 613 char c;
615 int rc; 614 int rc;
616 615
617 rc = get_user(c, buffer); 616 rc = get_user(c, buffer);
618 if (rc) 617 if (rc)
619 return rc; 618 return rc;
620 if (c == '0' || c == 'n' || c == 'N') 619 if (c == '0' || c == 'n' || c == 'N')
621 experimEnabled = 0; 620 experimEnabled = 0;
622 else if (c == '1' || c == 'y' || c == 'Y') 621 else if (c == '1' || c == 'y' || c == 'Y')
623 experimEnabled = 1; 622 experimEnabled = 1;
623 else if (c == '2')
624 experimEnabled = 2;
624 625
625 return count; 626 return count;
626} 627}
627 628
628static int 629static int
@@ -632,8 +633,6 @@ linuxExtensionsEnabled_read(char *page, char **start, off_t off,
632 int len; 633 int len;
633 634
634 len = sprintf(page, "%d\n", linuxExtEnabled); 635 len = sprintf(page, "%d\n", linuxExtEnabled);
635/* could also check if quotas are enabled in kernel
636 as a whole first */
637 len -= off; 636 len -= off;
638 *start = page + off; 637 *start = page + off;
639 638
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index ba90903909a6..582d66ca6da5 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -733,7 +733,7 @@ cifs_init_request_bufs(void)
733 kmem_cache_destroy(cifs_req_cachep); 733 kmem_cache_destroy(cifs_req_cachep);
734 return -ENOMEM; 734 return -ENOMEM;
735 } 735 }
736 /* 256 (MAX_CIFS_HDR_SIZE bytes is enough for most SMB responses and 736 /* MAX_CIFS_SMALL_BUFFER_SIZE bytes is enough for most SMB responses and
737 almost all handle based requests (but not write response, nor is it 737 almost all handle based requests (but not write response, nor is it
738 sufficient for path based requests). A smaller size would have 738 sufficient for path based requests). A smaller size would have
739 been more efficient (compacting multiple slab items on one 4k page) 739 been more efficient (compacting multiple slab items on one 4k page)
@@ -742,7 +742,8 @@ cifs_init_request_bufs(void)
742 efficient to alloc 1 per page off the slab compared to 17K (5page) 742 efficient to alloc 1 per page off the slab compared to 17K (5page)
743 alloc of large cifs buffers even when page debugging is on */ 743 alloc of large cifs buffers even when page debugging is on */
744 cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq", 744 cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq",
745 MAX_CIFS_HDR_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); 745 MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN,
746 NULL, NULL);
746 if (cifs_sm_req_cachep == NULL) { 747 if (cifs_sm_req_cachep == NULL) {
747 mempool_destroy(cifs_req_poolp); 748 mempool_destroy(cifs_req_poolp);
748 kmem_cache_destroy(cifs_req_cachep); 749 kmem_cache_destroy(cifs_req_cachep);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index c011c278af4c..862e403ff211 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -285,6 +285,7 @@ struct cifs_search_info {
285 unsigned endOfSearch:1; 285 unsigned endOfSearch:1;
286 unsigned emptyDir:1; 286 unsigned emptyDir:1;
287 unsigned unicode:1; 287 unsigned unicode:1;
288 unsigned smallBuf:1; /* so we know which buf_release function to call */
288}; 289};
289 290
290struct cifsFileInfo { 291struct cifsFileInfo {
@@ -420,7 +421,12 @@ struct dir_notify_req {
420#define MID_RESPONSE_RECEIVED 4 421#define MID_RESPONSE_RECEIVED 4
421#define MID_RETRY_NEEDED 8 /* session closed while this request out */ 422#define MID_RETRY_NEEDED 8 /* session closed while this request out */
422#define MID_NO_RESP_NEEDED 0x10 423#define MID_NO_RESP_NEEDED 0x10
423#define MID_SMALL_BUFFER 0x20 /* 112 byte response buffer instead of 4K */ 424
425/* Types of response buffer returned from SendReceive2 */
426#define CIFS_NO_BUFFER 0 /* Response buffer not returned */
427#define CIFS_SMALL_BUFFER 1
428#define CIFS_LARGE_BUFFER 2
429#define CIFS_IOVEC 4 /* array of response buffers */
424 430
425/* 431/*
426 ***************************************************************** 432 *****************************************************************
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 5253e779b3aa..3c09fb9cc569 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -80,7 +80,11 @@
80#define NT_TRANSACT_GET_USER_QUOTA 0x07 80#define NT_TRANSACT_GET_USER_QUOTA 0x07
81#define NT_TRANSACT_SET_USER_QUOTA 0x08 81#define NT_TRANSACT_SET_USER_QUOTA 0x08
82 82
83#define MAX_CIFS_HDR_SIZE 256 /* is future chained NTCreateXReadX bigger? */ 83#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */
84/* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */
85/* among the requests (NTCreateX response is bigger with wct of 34) */
86#define MAX_CIFS_HDR_SIZE 0x58 /* 4 len + 32 hdr + (2*24 wct) + 2 bct + 2 pad */
87#define CIFS_SMALL_PATH 120 /* allows for (448-88)/3 */
84 88
85/* internal cifs vfs structures */ 89/* internal cifs vfs structures */
86/***************************************************************** 90/*****************************************************************
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index c058f8a45b2b..8ef0ce47f5b6 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -49,7 +49,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
49 int * /* bytes returned */ , const int long_op); 49 int * /* bytes returned */ , const int long_op);
50extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, 50extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
51 struct kvec *, int /* nvec to send */, 51 struct kvec *, int /* nvec to send */,
52 int * /* bytes returned */ , const int long_op); 52 int * /* type of buf returned */ , const int long_op);
53extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); 53extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
54extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); 54extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
55extern int is_valid_oplock_break(struct smb_hdr *smb); 55extern int is_valid_oplock_break(struct smb_hdr *smb);
@@ -93,11 +93,12 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
93 const struct nls_table *); 93 const struct nls_table *);
94 94
95extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, 95extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
96 const char *searchName, const struct nls_table *nls_codepage, 96 const char *searchName, const struct nls_table *nls_codepage,
97 __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep); 97 __u16 *searchHandle, struct cifs_search_info * psrch_inf,
98 int map, const char dirsep);
98 99
99extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, 100extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
100 __u16 searchHandle, struct cifs_search_info * psrch_inf); 101 __u16 searchHandle, struct cifs_search_info * psrch_inf);
101 102
102extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, 103extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
103 const __u16 search_handle); 104 const __u16 search_handle);
@@ -230,8 +231,9 @@ extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
230 const int smb_file_id); 231 const int smb_file_id);
231 232
232extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, 233extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
233 const int netfid, unsigned int count, 234 const int netfid, unsigned int count,
234 const __u64 lseek, unsigned int *nbytes, char **buf); 235 const __u64 lseek, unsigned int *nbytes, char **buf,
236 int * return_buf_type);
235extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, 237extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
236 const int netfid, const unsigned int count, 238 const int netfid, const unsigned int count,
237 const __u64 lseek, unsigned int *nbytes, 239 const __u64 lseek, unsigned int *nbytes,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 3565d3bf2e32..1620991cd4d2 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -958,21 +958,19 @@ openRetry:
958 return rc; 958 return rc;
959} 959}
960 960
961/* If no buffer passed in, then caller wants to do the copy
962 as in the case of readpages so the SMB buffer must be
963 freed by the caller */
964
965int 961int
966CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, 962CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
967 const int netfid, const unsigned int count, 963 const int netfid, const unsigned int count,
968 const __u64 lseek, unsigned int *nbytes, char **buf) 964 const __u64 lseek, unsigned int *nbytes, char **buf,
965 int * pbuf_type)
969{ 966{
970 int rc = -EACCES; 967 int rc = -EACCES;
971 READ_REQ *pSMB = NULL; 968 READ_REQ *pSMB = NULL;
972 READ_RSP *pSMBr = NULL; 969 READ_RSP *pSMBr = NULL;
973 char *pReadData = NULL; 970 char *pReadData = NULL;
974 int bytes_returned;
975 int wct; 971 int wct;
972 int resp_buf_type = 0;
973 struct kvec iov[1];
976 974
977 cFYI(1,("Reading %d bytes on fid %d",count,netfid)); 975 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
978 if(tcon->ses->capabilities & CAP_LARGE_FILES) 976 if(tcon->ses->capabilities & CAP_LARGE_FILES)
@@ -981,8 +979,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
981 wct = 10; /* old style read */ 979 wct = 10; /* old style read */
982 980
983 *nbytes = 0; 981 *nbytes = 0;
984 rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB, 982 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
985 (void **) &pSMBr);
986 if (rc) 983 if (rc)
987 return rc; 984 return rc;
988 985
@@ -990,13 +987,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
990 if (tcon->ses->server == NULL) 987 if (tcon->ses->server == NULL)
991 return -ECONNABORTED; 988 return -ECONNABORTED;
992 989
993 pSMB->AndXCommand = 0xFF; /* none */ 990 pSMB->AndXCommand = 0xFF; /* none */
994 pSMB->Fid = netfid; 991 pSMB->Fid = netfid;
995 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); 992 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
996 if(wct == 12) 993 if(wct == 12)
997 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); 994 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
998 else if((lseek >> 32) > 0) /* can not handle this big offset for old */ 995 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
999 return -EIO; 996 return -EIO;
1000 997
1001 pSMB->Remaining = 0; 998 pSMB->Remaining = 0;
1002 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); 999 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
@@ -1005,14 +1002,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
1005 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */ 1002 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1006 else { 1003 else {
1007 /* old style read */ 1004 /* old style read */
1008 struct smb_com_readx_req * pSMBW = 1005 struct smb_com_readx_req * pSMBW =
1009 (struct smb_com_readx_req *)pSMB; 1006 (struct smb_com_readx_req *)pSMB;
1010 pSMBW->ByteCount = 0; 1007 pSMBW->ByteCount = 0;
1011 } 1008 }
1012 1009
1013 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 1010 iov[0].iov_base = (char *)pSMB;
1014 (struct smb_hdr *) pSMBr, &bytes_returned, 0); 1011 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1012 rc = SendReceive2(xid, tcon->ses, iov,
1013 1 /* num iovecs */,
1014 &resp_buf_type, 0);
1015 cifs_stats_inc(&tcon->num_reads); 1015 cifs_stats_inc(&tcon->num_reads);
1016 pSMBr = (READ_RSP *)iov[0].iov_base;
1016 if (rc) { 1017 if (rc) {
1017 cERROR(1, ("Send error in read = %d", rc)); 1018 cERROR(1, ("Send error in read = %d", rc));
1018 } else { 1019 } else {
@@ -1022,33 +1023,43 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
1022 *nbytes = data_length; 1023 *nbytes = data_length;
1023 1024
1024 /*check that DataLength would not go beyond end of SMB */ 1025 /*check that DataLength would not go beyond end of SMB */
1025 if ((data_length > CIFSMaxBufSize) 1026 if ((data_length > CIFSMaxBufSize)
1026 || (data_length > count)) { 1027 || (data_length > count)) {
1027 cFYI(1,("bad length %d for count %d",data_length,count)); 1028 cFYI(1,("bad length %d for count %d",data_length,count));
1028 rc = -EIO; 1029 rc = -EIO;
1029 *nbytes = 0; 1030 *nbytes = 0;
1030 } else { 1031 } else {
1031 pReadData = 1032 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1032 (char *) (&pSMBr->hdr.Protocol) +
1033 le16_to_cpu(pSMBr->DataOffset); 1033 le16_to_cpu(pSMBr->DataOffset);
1034/* if(rc = copy_to_user(buf, pReadData, data_length)) { 1034/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1035 cERROR(1,("Faulting on read rc = %d",rc)); 1035 cERROR(1,("Faulting on read rc = %d",rc));
1036 rc = -EFAULT; 1036 rc = -EFAULT;
1037 }*/ /* can not use copy_to_user when using page cache*/ 1037 }*/ /* can not use copy_to_user when using page cache*/
1038 if(*buf) 1038 if(*buf)
1039 memcpy(*buf,pReadData,data_length); 1039 memcpy(*buf,pReadData,data_length);
1040 } 1040 }
1041 } 1041 }
1042 if(*buf)
1043 cifs_buf_release(pSMB);
1044 else
1045 *buf = (char *)pSMB;
1046 1042
1047 /* Note: On -EAGAIN error only caller can retry on handle based calls 1043 cifs_small_buf_release(pSMB);
1044 if(*buf) {
1045 if(resp_buf_type == CIFS_SMALL_BUFFER)
1046 cifs_small_buf_release(iov[0].iov_base);
1047 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1048 cifs_buf_release(iov[0].iov_base);
1049 } else /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ {
1050 *buf = iov[0].iov_base;
1051 if(resp_buf_type == CIFS_SMALL_BUFFER)
1052 *pbuf_type = CIFS_SMALL_BUFFER;
1053 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1054 *pbuf_type = CIFS_LARGE_BUFFER;
1055 }
1056
1057 /* Note: On -EAGAIN error only caller can retry on handle based calls
1048 since file handle passed in no longer valid */ 1058 since file handle passed in no longer valid */
1049 return rc; 1059 return rc;
1050} 1060}
1051 1061
1062
1052int 1063int
1053CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, 1064CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1054 const int netfid, const unsigned int count, 1065 const int netfid, const unsigned int count,
@@ -1163,10 +1174,10 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1163{ 1174{
1164 int rc = -EACCES; 1175 int rc = -EACCES;
1165 WRITE_REQ *pSMB = NULL; 1176 WRITE_REQ *pSMB = NULL;
1166 int bytes_returned, wct; 1177 int wct;
1167 int smb_hdr_len; 1178 int smb_hdr_len;
1179 int resp_buf_type = 0;
1168 1180
1169 /* BB removeme BB */
1170 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count)); 1181 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1171 1182
1172 if(tcon->ses->capabilities & CAP_LARGE_FILES) 1183 if(tcon->ses->capabilities & CAP_LARGE_FILES)
@@ -1209,22 +1220,34 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1209 pSMBW->ByteCount = cpu_to_le16(count + 5); 1220 pSMBW->ByteCount = cpu_to_le16(count + 5);
1210 } 1221 }
1211 iov[0].iov_base = pSMB; 1222 iov[0].iov_base = pSMB;
1212 iov[0].iov_len = smb_hdr_len + 4; 1223 if(wct == 14)
1224 iov[0].iov_len = smb_hdr_len + 4;
1225 else /* wct == 12 pad bigger by four bytes */
1226 iov[0].iov_len = smb_hdr_len + 8;
1227
1213 1228
1214 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned, 1229 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1215 long_op); 1230 long_op);
1216 cifs_stats_inc(&tcon->num_writes); 1231 cifs_stats_inc(&tcon->num_writes);
1217 if (rc) { 1232 if (rc) {
1218 cFYI(1, ("Send error Write2 = %d", rc)); 1233 cFYI(1, ("Send error Write2 = %d", rc));
1219 *nbytes = 0; 1234 *nbytes = 0;
1235 } else if(resp_buf_type == 0) {
1236 /* presumably this can not happen, but best to be safe */
1237 rc = -EIO;
1238 *nbytes = 0;
1220 } else { 1239 } else {
1221 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB; 1240 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1222 *nbytes = le16_to_cpu(pSMBr->CountHigh); 1241 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1223 *nbytes = (*nbytes) << 16; 1242 *nbytes = (*nbytes) << 16;
1224 *nbytes += le16_to_cpu(pSMBr->Count); 1243 *nbytes += le16_to_cpu(pSMBr->Count);
1225 } 1244 }
1226 1245
1227 cifs_small_buf_release(pSMB); 1246 cifs_small_buf_release(pSMB);
1247 if(resp_buf_type == CIFS_SMALL_BUFFER)
1248 cifs_small_buf_release(iov[0].iov_base);
1249 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1250 cifs_buf_release(iov[0].iov_base);
1228 1251
1229 /* Note: On -EAGAIN error only caller can retry on handle based calls 1252 /* Note: On -EAGAIN error only caller can retry on handle based calls
1230 since file handle passed in no longer valid */ 1253 since file handle passed in no longer valid */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 651f3b6cebed..45c9d726c002 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -514,7 +514,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
514 /* else length ok */ 514 /* else length ok */
515 reconnect = 0; 515 reconnect = 0;
516 516
517 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { 517 if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
518 isLargeBuf = TRUE; 518 isLargeBuf = TRUE;
519 memcpy(bigbuf, smallbuf, 4); 519 memcpy(bigbuf, smallbuf, 4);
520 smb_buffer = bigbuf; 520 smb_buffer = bigbuf;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index b67be3d8c019..c249b628fd1c 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -555,13 +555,13 @@ int cifs_closedir(struct inode *inode, struct file *file)
555 } 555 }
556 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; 556 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
557 if (ptmp) { 557 if (ptmp) {
558 /* BB removeme BB */ cFYI(1, ("freeing smb buf in srch struct in closedir")); 558 cFYI(1, ("closedir free smb buf in srch struct"));
559 pCFileStruct->srch_inf.ntwrk_buf_start = NULL; 559 pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
560 cifs_buf_release(ptmp); 560 cifs_buf_release(ptmp);
561 } 561 }
562 ptmp = pCFileStruct->search_resume_name; 562 ptmp = pCFileStruct->search_resume_name;
563 if (ptmp) { 563 if (ptmp) {
564 /* BB removeme BB */ cFYI(1, ("freeing resume name in closedir")); 564 cFYI(1, ("closedir free resume name"));
565 pCFileStruct->search_resume_name = NULL; 565 pCFileStruct->search_resume_name = NULL;
566 kfree(ptmp); 566 kfree(ptmp);
567 } 567 }
@@ -871,8 +871,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
871 break; 871 break;
872 } 872 }
873 /* BB FIXME We can not sign across two buffers yet */ 873 /* BB FIXME We can not sign across two buffers yet */
874 if((experimEnabled) && ((pTcon->ses->server->secMode & 874 if((pTcon->ses->server->secMode &
875 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) { 875 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) {
876 struct kvec iov[2]; 876 struct kvec iov[2];
877 unsigned int len; 877 unsigned int len;
878 878
@@ -1424,6 +1424,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
1424 rc = -EAGAIN; 1424 rc = -EAGAIN;
1425 smb_read_data = NULL; 1425 smb_read_data = NULL;
1426 while (rc == -EAGAIN) { 1426 while (rc == -EAGAIN) {
1427 int buf_type = CIFS_NO_BUFFER;
1427 if ((open_file->invalidHandle) && 1428 if ((open_file->invalidHandle) &&
1428 (!open_file->closePend)) { 1429 (!open_file->closePend)) {
1429 rc = cifs_reopen_file(file->f_dentry->d_inode, 1430 rc = cifs_reopen_file(file->f_dentry->d_inode,
@@ -1432,20 +1433,22 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
1432 break; 1433 break;
1433 } 1434 }
1434 rc = CIFSSMBRead(xid, pTcon, 1435 rc = CIFSSMBRead(xid, pTcon,
1435 open_file->netfid, 1436 open_file->netfid,
1436 current_read_size, *poffset, 1437 current_read_size, *poffset,
1437 &bytes_read, &smb_read_data); 1438 &bytes_read, &smb_read_data,
1439 &buf_type);
1438 pSMBr = (struct smb_com_read_rsp *)smb_read_data; 1440 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1439 if (copy_to_user(current_offset, 1441 if (copy_to_user(current_offset,
1440 smb_read_data + 4 /* RFC1001 hdr */ 1442 smb_read_data + 4 /* RFC1001 hdr */
1441 + le16_to_cpu(pSMBr->DataOffset), 1443 + le16_to_cpu(pSMBr->DataOffset),
1442 bytes_read)) { 1444 bytes_read)) {
1443 rc = -EFAULT; 1445 rc = -EFAULT;
1444 FreeXid(xid); 1446 }
1445 return rc;
1446 }
1447 if (smb_read_data) { 1447 if (smb_read_data) {
1448 cifs_buf_release(smb_read_data); 1448 if(buf_type == CIFS_SMALL_BUFFER)
1449 cifs_small_buf_release(smb_read_data);
1450 else if(buf_type == CIFS_LARGE_BUFFER)
1451 cifs_buf_release(smb_read_data);
1449 smb_read_data = NULL; 1452 smb_read_data = NULL;
1450 } 1453 }
1451 } 1454 }
@@ -1478,6 +1481,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1478 int xid; 1481 int xid;
1479 char *current_offset; 1482 char *current_offset;
1480 struct cifsFileInfo *open_file; 1483 struct cifsFileInfo *open_file;
1484 int buf_type = CIFS_NO_BUFFER;
1481 1485
1482 xid = GetXid(); 1486 xid = GetXid();
1483 cifs_sb = CIFS_SB(file->f_dentry->d_sb); 1487 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
@@ -1514,9 +1518,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
1514 break; 1518 break;
1515 } 1519 }
1516 rc = CIFSSMBRead(xid, pTcon, 1520 rc = CIFSSMBRead(xid, pTcon,
1517 open_file->netfid, 1521 open_file->netfid,
1518 current_read_size, *poffset, 1522 current_read_size, *poffset,
1519 &bytes_read, &current_offset); 1523 &bytes_read, &current_offset,
1524 &buf_type);
1520 } 1525 }
1521 if (rc || (bytes_read == 0)) { 1526 if (rc || (bytes_read == 0)) {
1522 if (total_read) { 1527 if (total_read) {
@@ -1614,6 +1619,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
1614 struct smb_com_read_rsp *pSMBr; 1619 struct smb_com_read_rsp *pSMBr;
1615 struct pagevec lru_pvec; 1620 struct pagevec lru_pvec;
1616 struct cifsFileInfo *open_file; 1621 struct cifsFileInfo *open_file;
1622 int buf_type = CIFS_NO_BUFFER;
1617 1623
1618 xid = GetXid(); 1624 xid = GetXid();
1619 if (file->private_data == NULL) { 1625 if (file->private_data == NULL) {
@@ -1670,14 +1676,17 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
1670 } 1676 }
1671 1677
1672 rc = CIFSSMBRead(xid, pTcon, 1678 rc = CIFSSMBRead(xid, pTcon,
1673 open_file->netfid, 1679 open_file->netfid,
1674 read_size, offset, 1680 read_size, offset,
1675 &bytes_read, &smb_read_data); 1681 &bytes_read, &smb_read_data,
1676 1682 &buf_type);
1677 /* BB more RC checks ? */ 1683 /* BB more RC checks ? */
1678 if (rc== -EAGAIN) { 1684 if (rc== -EAGAIN) {
1679 if (smb_read_data) { 1685 if (smb_read_data) {
1680 cifs_buf_release(smb_read_data); 1686 if(buf_type == CIFS_SMALL_BUFFER)
1687 cifs_small_buf_release(smb_read_data);
1688 else if(buf_type == CIFS_LARGE_BUFFER)
1689 cifs_buf_release(smb_read_data);
1681 smb_read_data = NULL; 1690 smb_read_data = NULL;
1682 } 1691 }
1683 } 1692 }
@@ -1734,7 +1743,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
1734 break; 1743 break;
1735 } 1744 }
1736 if (smb_read_data) { 1745 if (smb_read_data) {
1737 cifs_buf_release(smb_read_data); 1746 if(buf_type == CIFS_SMALL_BUFFER)
1747 cifs_small_buf_release(smb_read_data);
1748 else if(buf_type == CIFS_LARGE_BUFFER)
1749 cifs_buf_release(smb_read_data);
1738 smb_read_data = NULL; 1750 smb_read_data = NULL;
1739 } 1751 }
1740 bytes_read = 0; 1752 bytes_read = 0;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index d1e995757436..f65310cc60a1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -229,11 +229,12 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
229 cifs_sb->mnt_cifs_flags & 229 cifs_sb->mnt_cifs_flags &
230 CIFS_MOUNT_MAP_SPECIAL_CHR); 230 CIFS_MOUNT_MAP_SPECIAL_CHR);
231 if (rc==0) { 231 if (rc==0) {
232 int buf_type = CIFS_NO_BUFFER;
232 /* Read header */ 233 /* Read header */
233 rc = CIFSSMBRead(xid, pTcon, 234 rc = CIFSSMBRead(xid, pTcon,
234 netfid, 235 netfid,
235 24 /* length */, 0 /* offset */, 236 24 /* length */, 0 /* offset */,
236 &bytes_read, &pbuf); 237 &bytes_read, &pbuf, &buf_type);
237 if((rc == 0) && (bytes_read >= 8)) { 238 if((rc == 0) && (bytes_read >= 8)) {
238 if(memcmp("IntxBLK", pbuf, 8) == 0) { 239 if(memcmp("IntxBLK", pbuf, 8) == 0) {
239 cFYI(1,("Block device")); 240 cFYI(1,("Block device"));
@@ -267,7 +268,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
267 } else { 268 } else {
268 inode->i_mode |= S_IFREG; /* then it is a file */ 269 inode->i_mode |= S_IFREG; /* then it is a file */
269 rc = -EOPNOTSUPP; /* or some unknown SFU type */ 270 rc = -EOPNOTSUPP; /* or some unknown SFU type */
270 } 271 }
271 CIFSSMBClose(xid, pTcon, netfid); 272 CIFSSMBClose(xid, pTcon, netfid);
272 } 273 }
273 return rc; 274 return rc;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index ac5a72a299a3..812c6bb0fe38 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -299,7 +299,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
299 struct cifsSesInfo * ses; 299 struct cifsSesInfo * ses;
300 char *temp = (char *) buffer; 300 char *temp = (char *) buffer;
301 301
302 memset(temp,0,MAX_CIFS_HDR_SIZE); 302 memset(temp,0,256); /* bigger than MAX_CIFS_HDR_SIZE */
303 303
304 buffer->smb_buf_length = 304 buffer->smb_buf_length =
305 (2 * word_count) + sizeof (struct smb_hdr) - 305 (2 * word_count) + sizeof (struct smb_hdr) -
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 0abfbf4e4a49..c96a148c39b2 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -298,7 +298,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
298 298
299int 299int
300SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 300SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
301 struct kvec *iov, int n_vec, int *pbytes_returned, 301 struct kvec *iov, int n_vec, int * pRespBufType /* ret */,
302 const int long_op) 302 const int long_op)
303{ 303{
304 int rc = 0; 304 int rc = 0;
@@ -306,6 +306,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
306 unsigned long timeout; 306 unsigned long timeout;
307 struct mid_q_entry *midQ; 307 struct mid_q_entry *midQ;
308 struct smb_hdr *in_buf = iov[0].iov_base; 308 struct smb_hdr *in_buf = iov[0].iov_base;
309
310 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
309 311
310 if (ses == NULL) { 312 if (ses == NULL) {
311 cERROR(1,("Null smb session")); 313 cERROR(1,("Null smb session"));
@@ -491,23 +493,20 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
491 if (midQ->resp_buf && 493 if (midQ->resp_buf &&
492 (midQ->midState == MID_RESPONSE_RECEIVED)) { 494 (midQ->midState == MID_RESPONSE_RECEIVED)) {
493 495
494 in_buf->smb_buf_length = receive_len; 496 iov[0].iov_base = (char *)midQ->resp_buf;
495 if(receive_len > 500) { 497 if(midQ->largeBuf)
496 /* use multiple buffers on way out */ 498 *pRespBufType = CIFS_LARGE_BUFFER;
497 } else { 499 else
498 memcpy((char *)in_buf + 4, 500 *pRespBufType = CIFS_SMALL_BUFFER;
499 (char *)midQ->resp_buf + 4, 501 iov[0].iov_len = receive_len + 4;
500 receive_len); 502 iov[1].iov_len = 0;
501 iov[0].iov_len = receive_len + 4;
502 iov[1].iov_len = 0;
503 }
504 503
505 dump_smb(in_buf, 80); 504 dump_smb(midQ->resp_buf, 80);
506 /* convert the length into a more usable form */ 505 /* convert the length into a more usable form */
507 if((receive_len > 24) && 506 if((receive_len > 24) &&
508 (ses->server->secMode & (SECMODE_SIGN_REQUIRED | 507 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
509 SECMODE_SIGN_ENABLED))) { 508 SECMODE_SIGN_ENABLED))) {
510 rc = cifs_verify_signature(in_buf, 509 rc = cifs_verify_signature(midQ->resp_buf,
511 ses->server->mac_signing_key, 510 ses->server->mac_signing_key,
512 midQ->sequence_number+1); 511 midQ->sequence_number+1);
513 if(rc) { 512 if(rc) {
@@ -516,18 +515,19 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
516 } 515 }
517 } 516 }
518 517
519 *pbytes_returned = in_buf->smb_buf_length;
520
521 /* BB special case reconnect tid and uid here? */ 518 /* BB special case reconnect tid and uid here? */
522 /* BB special case Errbadpassword and pwdexpired here */ 519 /* BB special case Errbadpassword and pwdexpired here */
523 rc = map_smb_to_linux_error(in_buf); 520 rc = map_smb_to_linux_error(midQ->resp_buf);
524 521
525 /* convert ByteCount if necessary */ 522 /* convert ByteCount if necessary */
526 if (receive_len >= 523 if (receive_len >=
527 sizeof (struct smb_hdr) - 524 sizeof (struct smb_hdr) -
528 4 /* do not count RFC1001 header */ + 525 4 /* do not count RFC1001 header */ +
529 (2 * in_buf->WordCount) + 2 /* bcc */ ) 526 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
530 BCC(in_buf) = le16_to_cpu(BCC_LE(in_buf)); 527 BCC(midQ->resp_buf) =
528 le16_to_cpu(BCC_LE(midQ->resp_buf));
529 midQ->resp_buf = NULL; /* mark it so will not be freed
530 by DeleteMidQEntry */
531 } else { 531 } else {
532 rc = -EIO; 532 rc = -EIO;
533 cFYI(1,("Bad MID state?")); 533 cFYI(1,("Bad MID state?"));
@@ -793,7 +793,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
793 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); 793 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
794 } else { 794 } else {
795 rc = -EIO; 795 rc = -EIO;
796 cERROR(1,("Bad MID state? ")); 796 cERROR(1,("Bad MID state?"));
797 } 797 }
798 } 798 }
799cifs_no_response_exit: 799cifs_no_response_exit: