diff options
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 */ |
