aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifssmb.c
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/cifs/cifssmb.c
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/cifs/cifssmb.c')
-rw-r--r--fs/cifs/cifssmb.c93
1 files changed, 58 insertions, 35 deletions
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 */