diff options
author | Steve French <sfrench@us.ibm.com> | 2005-12-12 23:53:18 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2005-12-12 23:53:18 -0500 |
commit | ec637e3ffb6b978143652477c7c5f96c9519b691 (patch) | |
tree | 32533b8f101e1d85b3499050eef29e78480e5cae /fs/cifs/cifssmb.c | |
parent | c89a86bb96307019867d11874ef0b86adaa0598e (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.c | 93 |
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 | |||
965 | int | 961 | int |
966 | CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | 962 | CIFSSMBRead(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 | |||
1052 | int | 1063 | int |
1053 | CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | 1064 | CIFSSMBWrite(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 */ |